use-effectreasonreason-react

useEffect vs useEffect0 in ReasonML


I am trying understand what the difference is between:

 React.useEffect(() => {
    let timerId = Js.Global.setInterval(() => tick(), 1000);
    Some(() => Js.Global.clearInterval(timerId));
  });
 React.useEffect0(() => {
    let timerId = Js.Global.setInterval(() => tick(), 1000);
    Some(() => Js.Global.clearInterval(timerId));
  });

They both have the same type signature and both compile but the useEffect0 does nothing:

// useEffect0 : unit => option(unit => unit) => unit
// useEffect : unit => option(unit => unit) => unit

To use the example at https://reasonml.github.io/reason-react/blog/2019/04/10/react-hooks, it uses useEffect but if you change so that it uses useState instead of useReducer you have to change useEffect to useEffect0

Original version using useEffect0:

type action =
  | Tick;

type state = {
  count: int,
};

[@react.component]
let make = () => {
  let (state, dispatch) = React.useReducer(
    (state, action) =>
      switch (action) {
      | Tick => {count: state.count + 1}
      },
    {count: 0}
  );

  React.useEffect0(() => {
    let timerId = Js.Global.setInterval(() => dispatch(Tick), 1000);
    Some(() => Js.Global.clearInterval(timerId))
  });

  <div>{ReasonReact.string(string_of_int(state.count))}</div>;
};

After removing useReducer and using useEffect:

[@react.component]
let make = () => {
let (state, dispatch) = React.useState(()=>
    {count: 0}
  );
let tick =()=> dispatch(_=>{count: state.count + 1});
  React.useEffect(() => {
    let timerId = Js.Global.setInterval(() => tick(), 1000);
    Some(() => Js.Global.clearInterval(timerId))
  });

  <div>{ReasonReact.string(string_of_int(state.count))}</div>;
};

So why does the call change when using the different structure?

Any links or explanation would be greatly appreciated.

Thank you.


Solution

  • React.useEffect(f) in Reason compiles to React.useEffect(f) in JavaScript. React.useEffect0(f) in Reason compiles to React.useEffect(f, []) in JavaScript.

    The difference is that second [] argument that's inserted in the JavaScript. By default, useEffect in JavaScript fires with every render. By adding the empty array in the second argument, we're telling React to only fire it once, when the component first renders.