ReasonReact's 0.7.0 release adds support for React hooks. It took me some googling and reading through
React.re to figure out how to use them all. Here they are in one place with usage examples.
React context and useContext
This was the least obvious to me but makes sense if you understand what
[@react.component]
is doing.
type theme = Dark | Light;
let themeContext: React.Context.t(theme) = React.createContext(Dark);
module ThemeProvider = {
let makeProps = (~value, ~children, ()) => {
"value": value,
"children": children,
};
let make = React.Context.provider(themeContext);
};
<ThemeProvider value=Light> children </ThemeProvider>;
let make = () => {
let theme = React.useContext(themeContext);
};
useState
useState
requires using the lazy initializer and the `
state => `state
version of
setState
. Without this constraint, Reason can't tell if you are providing a lazy initializer or have state of type
unit => 'a
. The ReasonReact
source says "we know this api isn't great. tl;dr useReducer instead" but I think it's quite usable.
let make = () => {
let (value, setValue) = React.useState(() => initialValue);
setValue(oldValue => newValue);
};
useReducer
type action = Increment | Decrement;
let reducer = (state, action) =>
switch (action) {
| Increment => state + 1
| Decrement => state - 1
};
let make = () => {
let (value, dispatch) = React.useReducer(reducer, 0);
dispatch(Increment);
};
Dependencies
useEffect
,
useLayoutEffect
,
useMemo
,
useCallback
, and
useImperativeHandle
take
dependencies. ReasonReact has distinct APIs for each length of dependencies. The variants are described once here with
useMemo
. The remainder core hooks with deps follow the same pattern.
React.useMemo(() => []);
React.useMemo0(() => []);
React.useMemo1(() => [value], [|value|]);
React.useMemo1(() => [value1, value2], [|value1, value2|]);
React.useMemo2(() => [arg1, arg2], (arg1, arg2));
React.useMemo3(() => [arg1, arg2, arg3], (arg1, arg2, arg3));
useEffect, useLayoutEffect
React.useEffect0(() => {
Js.log("mount");
None;
Some(() => Js.log("unmount"));
});
useRef
let myRef = React.useRef(initialValue);
let value = React.Ref.current(myRef);
React.Ref.setCurrent(myRef, newValue);
forwardRef
module MyInput = {
[@react.component]
let make = React.forwardRef((~label, ~value, theRef) =>
<div>
<label> {React.string(label)} </label>
<input
value
ref=?{Belt.Option.map(Js.Nullable.toOption(theRef), ReactDOMRe.Ref.domRef)}
/>
</div>
);
};
let make = () => {
let ref = React.useRef(Js.Nullable.null);
<MyInput label="Label" value="Value" ref />;
};