Force Component to re-render With Hooks in React
By: Harsh Patel
Tags: JavaScript, React, Programming, Hooks, Reactjs

Sometimes you suck at the situation where you want to re-render the component to state. Usually, this is not a good practice but still, there are ways to achieve this. React hooks supported >16.8 versions only.

Considering below hooks example

import { useState } from 'react'; function Example() {

const [count, setCount] = useState(0); return (

<div>

<p>You clicked {count} times</p>

<button onClick={() => setCount(count + 1)}>

Click me

</button>

</div>

);

}

Basically, you want to use this.forceUpdate() method to force the component to re-render immediately in React class components (ref below code for class component implementation)

class Test extends Component{

constructor(props){

super(props);

this.state = {

count:0,

count2: 100

}

this.setCount = this.setCount.bind(this);//how can I do this with hooks in functional component

}

setCount(){

let count = this.state.count;

count = count+1;

let count2 = this.state.count2;

count2 = count2+1;

this.setState({count});

this.forceUpdate();

//before below setState the component will re-render immediately when this.forceUpdate() is called

this.setState({count2: count

}



render(){

return (<div>

<span>Count: {this.state.count}></span>.

<button onClick={this.setCount}></button>

</div>

}

}

Now coming to the solution:

This is possible with useState or useReducer , since useState uses useReducer internally:

const [, updateState] = React.useState();

const forceUpdate = React.useCallback(() => updateState({}), []);

forceUpdate isn't intended to be used under normal circumstances, only in testing or other outstanding cases. This situation may be addressed in a more conventional way.

setCount is an example of improperly used forceUpdate , setState is asynchronous for performance reasons and shouldn't be forced to be synchronous just because state updates weren't performed correctly. If a state relies on a previously set state, this should be done with updater function,

If you need to set the state based on the previous state, read about the updater argument below. <…> Both state and props received by the updater function are guaranteed to be up-to-date. The output of the updater is shallowly merged with state.

setCount may not be an illustrative example because its purpose is unclear but this is the case for updater function:

setCount(){

this.setState(({count}) => ({ count: count + 1 }));

this.setState(({count2}) => ({ count2: count + 1 }));

this.setState(({count}) => ({ count2: count + 1 }));

}

This is translated 1:1 to hooks, with the exception that functions that are used as callbacks should better be memoized:

const [state, setState] = useState({ count: 0, count2: 100 }); const setCount = useCallback(() => {

setState(({count}) => ({ count: count + 1 }));

setState(({count2}) => ({ count2: count + 1 }));

setState(({count}) => ({ count2: count + 1 }));

}, []);

useCallback memoizes forceUpdate , so it stays constant during the component lifespan and can be passed as a prop safely. updateState({}) updates the state with a new object on each forceUpdate call, this results in a re-render. So yes, it forces an update when being called.

Hope you liked the solution.

Stay Updated ❤