Leon Chaewon Kong's dev blog

How to Implement React forceUpdate in Functional Component

Usually we modify states to update and re-render a component. It satisfies us mostly. But sometimes, we have to re-render the component manually.

Long long time ago, there were class-based components and they had something called forceUpdate. When you call forceUpdate function, it manually updated the component and make it to re-render.

Nowadays, almost nobody uses class-based components, and functional components and hooks dominates all over the world. We have magnificent hooks like useState, useEffect, useRef, useReducers, and so on. However, we no more have something simillar to forceUpdate.

TL;DR

You can use useReducer to create your own forceUpdate.

const [, forceUpdate] = useReducer(x => x + 1, 0);

function handleClick() {
  forceUpdate();
}

That’s all you need. I intentionally omitted the first element of the array, since we don’t need the value generated by useReducer.

How it works

From the hook’s name, you may got the meaning of it. Yeah, yeah, reducer.

useReducer

An alternative to useState. Accepts a reducer of type (state, action) => newState, and returns the current state paired with a dispatch method.

Whenever forceUpdate has been called, the useReducer hook increments the value by 1.

It’s somehow simmilar to code below:

const [state, setState] = useState(0);
const forceUpdate = () => setState(state + 1);

Advanced

How to update the component by force whenever resize event has captured?

import React, { useReducer, useLayoutEffect } from 'react';

const ResizableComponent = () => {
  const [, forceUpdate] = useReducer(x => x + 1, 0);

  useLayoutEffect(() => {
    window.addEventListener('resize', forceUpdate);

    return () => window.removeEventListener('resize', forceUpdate);
  }, []);
}

First, I used useLayoutEffect hook from React, which is pretty much about the same as useEffect, but the followings are different:

The signature is identical to useEffect, but it fires synchronously after all DOM mutations. Use this to read layout from the DOM and synchronously re-render. Updates scheduled inside useLayoutEffect will be flushed synchronously, before the browser has a chance to paint.

Then, I created a event-listener to capture resize event. window.addEventListener('resize', forceUpdate);

Finally I set useLayoutEffect to return a function, to clean-up event-listener.

From the guide:

Often, effects create resources that need to be cleaned up before the component leaves the screen, such as a subscription or timer ID. To do this, the function passed to useEffect may return a clean-up function.

Conclusion

By using useReducer, it is easy to implement forceUpdate in functional component. Yet, it is not quite recommended to use forceUpdate in React world, so, use it carefully and wisely.

Reference