I’m working on expanding the https://nextjs.orgwith-reasonml example to show both a persisted state (shared component?) and an internal component state. A couple things:
I’m a react newby, so is my usage of React.useReducer correct?
Does anyone know why the initial call to dispatch is duplicated?
I’ve updated the implementation to use a custom hook. I muddled around with using the Context API but found that it was very confusing to me and required me to mix in a lot of JavaScript.
Benefits of the custom hook implementation
All concerns are separated nicely
No new raw JavaScript code was required.
Duplicate increment issue on first click after load was solved.
Important code bits.
First I used the reducer hook because of the following note in the reason-react code:
Custom Hook Implementation
/*
## Global Count
This captures the count globally so that it will be persisted across
the `Index` and `About` pages. This replicates the functionality
of the shared-modules example.
*/
type t = ref(int);
type action =
| Increment;
let current = ref(0);
let increment = () => {
current := current^ + 1;
current;
};
let reducer = (_state, action) => {
switch(action) {
| Increment =>
let updated = increment();
updated^
}
};
let useGlobalCount = () => React.useReducer(reducer, current^);
This is just a simple global reference wrapped up in a reducer hook interface. This allows the calling component to use this like it would any other reducer hook.
Custom Hook Usage
/*
This is the set of action messages which are produced by this component.
* Add updates the components internal state.
*/
type action =
| Add
/*
This is the components internal state representation. This state object
is unique to each instance of the component.
*/
type state = {
count: int,
};
let counterReducer = (state, action) =>
switch(action) {
| Add => { count: state.count + 1 }
};
[@react.component]
let make = () => {
let (state, dispatch) = React.useReducer(counterReducer, { count: 0 });
let (globalState, globalDispatch) = GlobalCount.useGlobalCount();
let countMsg = "Count: " ++ string_of_int(state.count);
let persistentCountMsg = "Persistent Count " ++ string_of_int(globalState);
<div>
<p> {ReasonReact.string(countMsg)} </p>
<button onClick={_ => dispatch(Add)}> {React.string("Add")} </button>
<p> {ReasonReact.string(persistentCountMsg)} </p>
<button onClick={_ => globalDispatch(GlobalCount.Increment)}>
{React.string("Add")}
</button>
</div>;
};
let default = make;
Here the important things to notice are how the usage of the GlobalCount module maps directly to the usage of the React.useReducer module.
Hopefully this is a helpful example usage of custom hooks.