├── .gitignore
├── .npmignore
├── README.md
├── bsconfig.json
├── bundle
├── index.html
└── index.js
├── example
├── bsconfig.json
├── package.json
├── public
│ └── index.html
├── src
│ └── App.re
└── yarn.lock
├── package.json
├── src
├── Hooks.re
└── Hooks.rei
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | lib
3 | bundle
4 | .merlin
5 | .bsb.lock
6 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | exmaple
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # hooks-experimental
2 | An experiment using react's new "hooks" with ReasonReact
3 |
4 | WARNING: Do not use for anything real.
5 |
6 | ## How to use
7 |
8 | ### 1) the package.json
9 |
10 | NOTE: You *must* use yarn, so that we can override reason-react's react dependencies with `resolutions`.
11 |
12 | ```
13 | "resolutions": {
14 | "**/react": "16.7.0-alpha.0",
15 | "**/react-dom": "16.7.0-alpha.0"
16 | },
17 | "dependencies": {
18 | "react": "16.7.0-alpha.0",
19 | "react-dom": "16.7.0-alpha.0",
20 | "reason-react": "^0.5.3",
21 | "hooks-experimental": "github:jaredly/hooks-experimental"
22 | }
23 | ```
24 |
25 | ### 2) the bsconfig.json
26 |
27 | Nothing special here, just add `"hooks-experimental"` to `"bs-dependencies"`.
28 |
29 | ### 3) making a component!
30 |
31 | ```re
32 | module ReasonReact = Hooks.ReasonReact;
33 |
34 | module FancyCounter = {
35 | let component = (. props: {. "initialValue": int}) => {
36 | let (count, setCount) = Hooks.useState(props##initialValue);
37 |
38 |
39 |
{ReasonReact.string(string_of_int(count))}
40 |
43 | ;
44 | };
45 | component->Hooks.setName("Just");
46 |
47 | let make = (~initialValue, _children) =>
48 | Hooks.createElement(
49 | ~component,
50 | ~props={"initialValue": initialValue},
51 | );
52 | };
53 |
54 | ReactDOMRe.renderToElementWithId(, "root");
55 | ```
56 |
57 | ### 4) Hooks API
58 |
59 | ```
60 | [@bs.module "react"] external useState: 'a => ('a, (. 'a) => unit) = "";
61 |
62 | [@bs.module "react"] external useEffect: ((unit) => (unit => unit)) => unit = "";
63 | [@bs.module "react"]
64 | external useMutationEffect: ((unit) => (unit => unit)) => unit = "";
65 | [@bs.module "react"]
66 | external useLayoutEffect: ((unit) => (unit => unit)) => unit = "";
67 |
68 | [@bs.module "react"]
69 | external useEffectWithoutCleanup: (unit => unit) => unit = "useEffect";
70 | [@bs.module "react"]
71 | external useMutationEffectWithoutCleanup: (unit => unit) => unit = "";
72 | [@bs.module "react"]
73 | external useLayoutEffectWithoutCleanup: (unit => unit) => unit = "";
74 |
75 | [@bs.module "react"] external useCallback: (unit => 'a, 'b, unit) => 'a = "";
76 | [@bs.module "react"] external useMemo: (unit => 'a, 'b) => 'a = "";
77 |
78 | [@bs.module "react"] external useRef: 'a => {. "current": 'a} = "";
79 | [@bs.module "react"]
80 | external useDomRef: unit => {. "current": option(Dom.node)} = "useRef";
81 |
82 | [@bs.module "react"]
83 | external useReducer:
84 | (~reducer: (. 'state, 'action) => 'state, ~initial: 'state) =>
85 | ('state, (. 'action) => unit) =
86 | "";
87 | ```
--------------------------------------------------------------------------------
/bsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hooks-experimental",
3 | "sources": "src",
4 | "reason": {
5 | "react-jsx": 2
6 | },
7 | "bs-dependencies": ["reason-react"],
8 | "refmt": 3
9 | }
--------------------------------------------------------------------------------
/bundle/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | React Hooks!
4 |
5 |
6 |
7 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/example/bsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hooks-example",
3 | "sources": "src",
4 | "reason": {
5 | "react-jsx": 2
6 | },
7 | "bs-dependencies": ["reason-react", "hooks-experimental"],
8 | "refmt": 3
9 | }
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hooks-example",
3 | "dependencies": {
4 | "bs-platform": "^4.0.7",
5 | "fpack": "^0.6.8",
6 | "react": "16.7.0-alpha.0",
7 | "react-dom": "16.7.0-alpha.0",
8 | "reason-react": "^0.5.3",
9 | "hooks-experimental": "file:../"
10 | },
11 | "scripts": {
12 | "start": "bsb -make-world -w",
13 | "pack": "fpack serve lib/js/src/App.js -p 3010"
14 | },
15 | "resolutions": {
16 | "**/react": "16.7.0-alpha.0",
17 | "**/react-dom": "16.7.0-alpha.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/example/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | React Hooks!
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/src/App.re:
--------------------------------------------------------------------------------
1 |
2 | /* this file uses function components */
3 | module ReasonReact = Hooks.ReasonReact;
4 |
5 | module Just = {
6 | let component =
7 | (. props: {. "initialValue": int}) => {
8 | let (count, setCount) = Hooks.useState(props##initialValue);
9 | let (show, setShown) = Hooks.useState(true);
10 |
11 |
12 | {
13 | show ?
14 |
{ReasonReact.string(string_of_int(count))}
15 | : ReasonReact.null
16 | }
17 |
20 |
23 | ;
24 | };
25 | component->Hooks.setName("Just");
26 |
27 | let make = (~initialValue, _children) =>
28 | Hooks.createElement(
29 | ~component,
30 | ~props={"initialValue": initialValue},
31 | );
32 | };
33 |
34 | ReactDOMRe.renderToElementWithId(, "root");
35 |
--------------------------------------------------------------------------------
/example/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | bs-platform@^4.0.7:
6 | version "4.0.7"
7 | resolved "https://registry.yarnpkg.com/bs-platform/-/bs-platform-4.0.7.tgz#1a0bbf0fef439fef5f1a88ba60d5ac8a6d73570c"
8 |
9 | fpack@^0.6.8:
10 | version "0.6.8"
11 | resolved "https://registry.yarnpkg.com/fpack/-/fpack-0.6.8.tgz#a3c34b42a68c836ab0933e0cff1656ac39eb2092"
12 |
13 | "hooks-experimental@file:..":
14 | version "0.0.0-alpha"
15 | dependencies:
16 | bs-platform "^4.0.7"
17 | fpack "^0.6.8"
18 | react "16.7.0-alpha.0"
19 | react-dom "16.7.0-alpha.0"
20 | reason-react "^0.5.3"
21 |
22 | "js-tokens@^3.0.0 || ^4.0.0":
23 | version "4.0.0"
24 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
25 |
26 | loose-envify@^1.1.0, loose-envify@^1.3.1:
27 | version "1.4.0"
28 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
29 | dependencies:
30 | js-tokens "^3.0.0 || ^4.0.0"
31 |
32 | object-assign@^4.1.1:
33 | version "4.1.1"
34 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
35 |
36 | prop-types@^15.6.2:
37 | version "15.6.2"
38 | resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
39 | dependencies:
40 | loose-envify "^1.3.1"
41 | object-assign "^4.1.1"
42 |
43 | react-dom@16.7.0-alpha.0, "react-dom@>=15.0.0 || >=16.0.0":
44 | version "16.7.0-alpha.0"
45 | resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.7.0-alpha.0.tgz#8379158d4c76d63c989f325f45dfa5762582584f"
46 | dependencies:
47 | loose-envify "^1.1.0"
48 | object-assign "^4.1.1"
49 | prop-types "^15.6.2"
50 | scheduler "^0.11.0-alpha.0"
51 |
52 | react@16.7.0-alpha.0, "react@>=15.0.0 || >=16.0.0":
53 | version "16.7.0-alpha.0"
54 | resolved "https://registry.yarnpkg.com/react/-/react-16.7.0-alpha.0.tgz#e2ed4abe6f268c9b092a1d1e572953684d1783a9"
55 | dependencies:
56 | loose-envify "^1.1.0"
57 | object-assign "^4.1.1"
58 | prop-types "^15.6.2"
59 | scheduler "^0.11.0-alpha.0"
60 |
61 | reason-react@^0.5.3:
62 | version "0.5.3"
63 | resolved "https://registry.yarnpkg.com/reason-react/-/reason-react-0.5.3.tgz#10601809742fd991109ec9d69ad4baf2c3f17540"
64 | dependencies:
65 | react ">=15.0.0 || >=16.0.0"
66 | react-dom ">=15.0.0 || >=16.0.0"
67 |
68 | scheduler@^0.11.0-alpha.0:
69 | version "0.11.0-alpha.0"
70 | resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.11.0-alpha.0.tgz#7b132c726608993471db07866f2d59a52b9e190b"
71 | dependencies:
72 | loose-envify "^1.1.0"
73 | object-assign "^4.1.1"
74 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hooks-experimental",
3 | "version": "0.0.0-alpha.0",
4 | "dependencies": {
5 | "bs-platform": "^4.0.7",
6 | "fpack": "^0.6.8",
7 | "react": "16.7.0-alpha.0",
8 | "react-dom": "16.7.0-alpha.0",
9 | "reason-react": "^0.5.3"
10 | },
11 | "scripts": {
12 | "build": "bsb -make-world"
13 | },
14 | "resolutions": {
15 | "**/react": "16.7.0-alpha.0",
16 | "**/react-dom": "16.7.0-alpha.0"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Hooks.re:
--------------------------------------------------------------------------------
1 | [@bs.module "react"]
2 | external cloneElementOther:
3 | (ReasonReact.reactElement, 'props) => ReasonReact.reactElement =
4 | "cloneElement";
5 |
6 | module ReasonReact = {
7 | include ReasonReact;
8 | let element = (~key=?, ~ref=?, element) =>
9 | cloneElementOther(element, {"key": key, "ref": ref});
10 | };
11 |
12 | [@bs.set] external setName: ((. 'props) => ReasonReact.reactElement, string) => unit = "displayName";
13 |
14 | [@bs.module "react"] external useState: 'a => ('a, (. 'a) => unit) = "";
15 |
16 | [@bs.module "react"] external useEffect: ((unit) => ((. unit) => unit)) => unit = "";
17 | [@bs.module "react"]
18 | external useMutationEffect: ((unit) => ((. unit) => unit)) => unit = "";
19 | [@bs.module "react"]
20 | external useLayoutEffect: ((unit) => ((. unit) => unit)) => unit = "";
21 |
22 | [@bs.module "react"]
23 | external useEffectWithoutCleanup: (unit => unit) => unit = "useEffect";
24 | [@bs.module "react"]
25 | external useMutationEffectWithoutCleanup: (unit => unit) => unit = "";
26 | [@bs.module "react"]
27 | external useLayoutEffectWithoutCleanup: (unit => unit) => unit = "";
28 |
29 | [@bs.module "react"] external useCallback: (unit => 'a, 'b, unit) => 'a = "";
30 | [@bs.module "react"] external useMemo: (unit => 'a, 'b) => 'a = "";
31 |
32 | [@bs.module "react"] external useRef: 'a => {. "current": 'a} = "";
33 | [@bs.module "react"]
34 | external useDomRef: unit => {. "current": option(Dom.node)} = "useRef";
35 |
36 | [@bs.module "react"]
37 | external useReducer:
38 | (~reducer: (. 'state, 'action) => 'state, ~initial: 'state) =>
39 | ('state, (. 'action) => unit) =
40 | "";
41 |
42 | [@bs.module "react"]
43 | external createElement:
44 | (
45 | ~component: (. Js.t({..} as 'a)) => ReasonReact.reactElement,
46 | ~props: Js.t({..} as 'a)
47 | ) =>
48 | ReasonReact.reactElement =
49 | "";
50 |
51 | /* Not doing useImperativeMethods because it's super confusing. */
--------------------------------------------------------------------------------
/src/Hooks.rei:
--------------------------------------------------------------------------------
1 | let cloneElementOther:
2 | (ReasonReact.reactElement, 'props) => ReasonReact.reactElement;
3 |
4 | module ReasonReact: {
5 | include (module type of ReasonReact) with type reactElement = ReasonReact.reactElement;
6 | let element:
7 | (~key: 'a=?, ~ref: 'b=?, ReasonReact.reactElement) =>
8 | ReasonReact.reactElement;
9 | };
10 |
11 | /* let setName: ((. 'props) => ReasonReact.reactElement, string) => unit;
12 | let useState: 'a => ('a, (. 'a) => unit);
13 | let useEffect: ((unit, unit) => unit) => unit;
14 | let useMutationEffect: ((unit, unit) => unit) => unit;
15 | let useLayoutEffect: ((unit, unit) => unit) => unit;
16 | let useEffectWithoutCleanup: (unit => unit) => unit;
17 | let useMutationEffectWithoutCleanup: (unit => unit) => unit;
18 | let useLayoutEffectWithoutCleanup: (unit => unit) => unit;
19 | let useCallback: (unit => 'a, 'b, unit) => 'a;
20 | let useMemo: (unit => 'a, 'b) => 'a;
21 | let useRef: 'a => {. "current": 'a};
22 | let useDomRef: unit => {. "current": option(Dom.node)};
23 | let useReducer:
24 | (~reducer: ('state, 'action) => 'state, ~initial: 'state) =>
25 | ('state, 'action => unit);
26 | let createElement:
27 | (
28 | ~component: (. Js.t({..} as 'a)) => ReasonReact.reactElement,
29 | ~props: Js.t('a)
30 | ) =>
31 | ReasonReact.reactElement; */
32 |
33 |
34 |
35 |
36 | [@bs.set] external setName: ((. 'props) => ReasonReact.reactElement, string) => unit = "displayName";
37 |
38 | [@bs.module "react"] external useState: 'a => ('a, (. 'a) => unit) = "";
39 |
40 |
41 | [@bs.module "react"] external useEffect: ((unit) => ((. unit) => unit)) => unit = "";
42 | [@bs.module "react"]
43 | external useMutationEffect: ((unit) => ((. unit) => unit)) => unit = "";
44 | [@bs.module "react"]
45 | external useLayoutEffect: ((unit) => ((. unit) => unit)) => unit = "";
46 |
47 |
48 | [@bs.module "react"]
49 | external useEffectWithoutCleanup: (unit => unit) => unit = "useEffect";
50 | [@bs.module "react"]
51 | external useMutationEffectWithoutCleanup: (unit => unit) => unit = "";
52 | [@bs.module "react"]
53 | external useLayoutEffectWithoutCleanup: (unit => unit) => unit = "";
54 |
55 | [@bs.module "react"] external useCallback: (unit => 'a, 'b, unit) => 'a = "";
56 | [@bs.module "react"] external useMemo: (unit => 'a, 'b) => 'a = "";
57 |
58 | [@bs.module "react"] external useRef: 'a => {. "current": 'a} = "";
59 | [@bs.module "react"]
60 | external useDomRef: unit => {. "current": option(Dom.node)} = "useRef";
61 |
62 | [@bs.module "react"]
63 | external useReducer:
64 | (~reducer: (. 'state, 'action) => 'state, ~initial: 'state) =>
65 | ('state, (. 'action) => unit) =
66 | "";
67 |
68 | [@bs.module "react"]
69 | external createElement:
70 | (
71 | ~component: (. Js.t({..} as 'a)) => ReasonReact.reactElement,
72 | ~props: Js.t({..} as 'a)
73 | ) =>
74 | ReasonReact.reactElement =
75 | "";
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | bs-platform@^4.0.7:
6 | version "4.0.7"
7 | resolved "https://registry.yarnpkg.com/bs-platform/-/bs-platform-4.0.7.tgz#1a0bbf0fef439fef5f1a88ba60d5ac8a6d73570c"
8 |
9 | fpack@^0.6.8:
10 | version "0.6.8"
11 | resolved "https://registry.yarnpkg.com/fpack/-/fpack-0.6.8.tgz#a3c34b42a68c836ab0933e0cff1656ac39eb2092"
12 |
13 | "js-tokens@^3.0.0 || ^4.0.0":
14 | version "4.0.0"
15 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
16 |
17 | loose-envify@^1.1.0, loose-envify@^1.3.1:
18 | version "1.4.0"
19 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
20 | dependencies:
21 | js-tokens "^3.0.0 || ^4.0.0"
22 |
23 | object-assign@^4.1.1:
24 | version "4.1.1"
25 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
26 |
27 | prop-types@^15.6.2:
28 | version "15.6.2"
29 | resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
30 | dependencies:
31 | loose-envify "^1.3.1"
32 | object-assign "^4.1.1"
33 |
34 | react-dom@16.7.0-alpha.0, "react-dom@>=15.0.0 || >=16.0.0":
35 | version "16.7.0-alpha.0"
36 | resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.7.0-alpha.0.tgz#8379158d4c76d63c989f325f45dfa5762582584f"
37 | dependencies:
38 | loose-envify "^1.1.0"
39 | object-assign "^4.1.1"
40 | prop-types "^15.6.2"
41 | scheduler "^0.11.0-alpha.0"
42 |
43 | react@16.7.0-alpha.0, "react@>=15.0.0 || >=16.0.0":
44 | version "16.7.0-alpha.0"
45 | resolved "https://registry.yarnpkg.com/react/-/react-16.7.0-alpha.0.tgz#e2ed4abe6f268c9b092a1d1e572953684d1783a9"
46 | dependencies:
47 | loose-envify "^1.1.0"
48 | object-assign "^4.1.1"
49 | prop-types "^15.6.2"
50 | scheduler "^0.11.0-alpha.0"
51 |
52 | reason-react@^0.5.3:
53 | version "0.5.3"
54 | resolved "https://registry.yarnpkg.com/reason-react/-/reason-react-0.5.3.tgz#10601809742fd991109ec9d69ad4baf2c3f17540"
55 | dependencies:
56 | react ">=15.0.0 || >=16.0.0"
57 | react-dom ">=15.0.0 || >=16.0.0"
58 |
59 | scheduler@^0.11.0-alpha.0:
60 | version "0.11.0-alpha.0"
61 | resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.11.0-alpha.0.tgz#7b132c726608993471db07866f2d59a52b9e190b"
62 | dependencies:
63 | loose-envify "^1.1.0"
64 | object-assign "^4.1.1"
65 |
--------------------------------------------------------------------------------