reactjsrenderreact-hooksmemoization

Update React Hooks State During Render Using useMemo


Can useMemo be used just to avoid extra referential equality checking code/vars when setting state during a render?

Example: useMemo with a setState during render taken from this rare documented use case:

function ScrollView({row}) {
  let [isScrolling, setIsScrolling] = useState(false);

  const lessCodeThanCheckingPrevRow = useMemo(
    () => {
      // Row changed since last render. Update isScrolling.
      setIsScrolling(true); // let's assume the simplest case where prevState isn't needed here
    },
    [row]
  );

  return `Scrolling down: ${isScrolling}`;
}

Above drastically reduces code and extra vars, only otherwise used for equality checks, so why do the docs imply referential equality checks should be done manually?


Solution

  • This seems to be an elegant way to reduce boiler plate to me. I created a codesandbox to validate its behaviour.

    const UnitUnderTest = ({prop}) => {
      let [someState, setSomeState] = useState(false);
    
      const lessCodeThanCheckingPrevRow = useMemo(
        () => setSomeState(current => !current), 
        [prop],
      );
    
      useEffect(() => console.log('update finished'), [prop])
    
      console.log('run component');
    
      return `State: ${someState}`;
    }
    
    const App = () => {
      const [prop, setProp] = useState(false);
      const handleClick = () => setProp(current => !current);
    
      return (
        <div>
          <button onClick={handleClick} >change prop</button>
          <UnitUnderTest prop={prop} />
        </div>
      )
    };
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);
    

    Edit recursing-hopper-4ynjm

    Output when clicking the button to change the prop passed to the component:

    > run component 
    > run component 
    > update finished 
    

    As you can see the component has been run twice before the update cycle completed. This is equivalent to the the behaviour of getDerivedStateFromProps.

    I guess that there is no deeper thought behind why the docs propose a slightly different technique. In a way this is a manual check too but in a neat way. +1 for the idea.