How can I force a component to re-render with hooks in React?

JavascriptReactjsReact NativeReact Hooks

Javascript Problem Overview


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 we use this.forceUpdate() method to force the component to re-render immediately in React class components like below example

    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>
        }
 }

But my query is How can I force above functional component to re-render immediately with hooks?

Javascript Solutions


Solution 1 - Javascript

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 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 }));
   }, []);

Solution 2 - Javascript

Generally, you can use any state handling approach you want to trigger an update.

#With TypeScript

codesandbox example

###useState

const forceUpdate: () => void = React.useState()[1].bind(null, {})  // see NOTE below

###useReducer const forceUpdate = React.useReducer(() => ({}), {})1 as () => void

###as custom hook

Just wrap whatever approach you prefer like this

function useForceUpdate(): () => void {
  return React.useReducer(() => ({}), {})[1] as () => void // <- paste here
}

##How this works?

"To trigger an update" means to tell React engine that some value has changed and that it should rerender your component.

[, setState] from useState() requires a parameter. We get rid of it by binding a fresh object {}.
() => ({}) in useReducer is a dummy reducer that returns a fresh object each time an action is dispatched.
{} (fresh object) is required so that it triggers an update by changing a reference in the state.

PS: useState just wraps useReducer internally. source

NOTE: Using .bind with useState causes a change in function reference between renders. It is possible to wrap it inside useCallback as already explained here, but then it wouldn't be a sexy one-liner™. The Reducer version already keeps reference equality between renders. This is important if you want to pass the forceUpdate function in props.

#plain JS

const forceUpdate = React.useState()[1].bind(null, {})  // see NOTE above
const forceUpdate = React.useReducer(() => ({}))[1]

Solution 3 - Javascript

React Hooks FAQ official solution for forceUpdate:

const [_, forceUpdate] = useReducer((x) => x + 1, 0);
// usage
<button onClick={forceUpdate}>Force update</button>
Working example

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

  return (
    <div>
      <button onClick={forceUpdate}>Force update</button>
      <p>Forced update {_} times</p>
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.1/umd/react.production.min.js" integrity="sha256-vMEjoeSlzpWvres5mDlxmSKxx6jAmDNY4zCt712YCI0=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.1/umd/react-dom.production.min.js" integrity="sha256-QQt6MpTdAD0DiPLhqhzVyPs1flIdstR4/R7x4GqCvZ4=" crossorigin="anonymous"></script>
<script>var useReducer = React.useReducer</script>
<div id="root"></div>

Solution 4 - Javascript

As the others have mentioned, useState works - here is how mobx-react-lite implements updates - you could do something similar.

Define a new hook, useForceUpdate -

import { useState, useCallback } from 'react'

export function useForceUpdate() {
  const [, setTick] = useState(0);
  const update = useCallback(() => {
    setTick(tick => tick + 1);
  }, [])
  return update;
}

and use it in a component -

const forceUpdate = useForceUpdate();
if (...) {
  forceUpdate(); // force re-render
}

See https://github.com/mobxjs/mobx-react-lite/blob/master/src/utils.ts and https://github.com/mobxjs/mobx-react-lite/blob/master/src/useObserver.ts

Solution 5 - Javascript

Alternative to @MinhKha's answer:

It can be much cleaner with useReducer:

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

Usage: forceUpdate() - cleaner without params

Solution 6 - Javascript

You can simply define the useState like that:

const [, forceUpdate] = React.useState(0);

And usage: forceUpdate(n => !n)

Hope this help !

Solution 7 - Javascript

You should preferably only have your component depend on state and props and it will work as expected, but if you really need a function to force the component to re-render, you could use the useState hook and call the function when needed.

Example

const { useState, useEffect } = React;

function Foo() {
  const [, forceUpdate] = useState();

  useEffect(() => {
    setTimeout(forceUpdate, 2000);
  }, []);

  return <div>{Date.now()}</div>;
}

ReactDOM.render(<Foo />, document.getElementById("root"));

<script src="https://unpkg.com/[email protected]/umd/react.production.min.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>

<div id="root"></div>

Solution 8 - Javascript

Simple code

const forceUpdate = React.useReducer(bool => !bool)[1];

Use:

forceUpdate();

Solution 9 - Javascript

Potential option is to force update only on specific component using key. Updating the key trigger a rendering of the component (which failed to update before)

For example:

const [tableKey, setTableKey] = useState(1);
...

useEffect(() => {
	...
	setTableKey(tableKey + 1);
}, [tableData]);

...
<DataTable
    key={tableKey}
    data={tableData}/>

Solution 10 - Javascript

You can (ab)use normal hooks to force a rerender by taking advantage of the fact that React doesn't print booleans in JSX code

// create a hook
const [forceRerender, setForceRerender] = React.useState(true);

// ...put this line where you want to force a rerender
setForceRerender(!forceRerender);

// ...make sure that {forceRerender} is "visible" in your js code
// ({forceRerender} will not actually be visible since booleans are
// not printed, but updating its value will nonetheless force a
// rerender)
return (
  <div>{forceRerender}</div>
)

Solution 11 - Javascript

One line solution:

const useForceUpdate = () => useState()[1];

useState returns a pair of values: the current state and a function that updates it - state and setter, here we are using only the setter in order to force re-render.

Solution 12 - Javascript

react-tidy has a custom hook just for doing that called useRefresh:

import React from 'react'
import {useRefresh} from 'react-tidy'

function App() {
  const refresh = useRefresh()
  return (
    <p>
      The time is {new Date()} <button onClick={refresh}>Refresh</button>
    </p>
  )
}

Learn more about this hook

Disclaimer I am the writer of this library.

Solution 13 - Javascript

My variation of forceUpdate is not via a counter but rather via an object:

// Emulates `forceUpdate()`
const [unusedState, setUnusedState] = useState()
const forceUpdate = useCallback(() => setUnusedState({}), [])

Because {} !== {} every time.

Solution 14 - Javascript

Solution in one single line:

const [,forceRender] = useReducer((s) => s+1, 0)

You can learn about useReducer here. https://reactjs.org/docs/hooks-reference.html#usereducer

Solution 15 - Javascript

This will render depending components 3 times (arrays with equal elements aren't equal):

const [msg, setMsg] = useState([""])

setMsg(["test"])
setMsg(["test"])
setMsg(["test"])

Solution 16 - Javascript

For regular React Class based components, refer to React Docs for the forceUpdate api at this URL. The docs mention that:

> Normally you should try to avoid all uses of forceUpdate() and only > read from this.props and this.state in render()

However, it is also mentioned in the docs that:

> If your render() method depends on some other data, you can tell React > that the component needs re-rendering by calling forceUpdate().

So, although use cases for using forceUpdate might be rare, and I have not used it ever, however I have seen it used by other developers in some legacy corporate projects that I have worked on.

So, for the equivalent functionality for Functional Components, refer to the React Docs for HOOKS at this URL. Per the above URL, one can use the "useReducer" hook to provide a forceUpdate functionality for Functional Components.

A working code sample that does not use state or props is provided below, which is also available on CodeSandbox at this URL

import React, { useReducer, useRef } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  // Use the useRef hook to store a mutable value inside a functional component for the counter
  let countref = useRef(0);

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

  function handleClick() {
    countref.current++;
    console.log("Count = ", countref.current);
    forceUpdate(); // If you comment this out, the date and count in the screen will not be updated
  }

  return (
    <div className="App">
      <h1> {new Date().toLocaleString()} </h1>
      <h2>You clicked {countref.current} times</h2>
      <button
        onClick={() => {
          handleClick();
        }}
      >
        ClickToUpdateDateAndCount
      </button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

NOTE: An alternate approach using the useState hook (instead of useReducer) is also available at this URL.

Solution 17 - Javascript

There are many ways to force re-render in Hook.

For me simple way with useState() and tip of reference object values.

const [, forceRender] = useState({});

// Anywhre
forceRender({});

Codesandbox Example

Solution 18 - Javascript

const useForceRender = () => {
  const [, forceRender] = useReducer(x => !x, true)
  return forceRender
}

Usage

function Component () {
  const forceRender = useForceRender() 
  useEffect(() => {
    // ...
    forceRender()
  }, [])

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHemadri DasariView Question on Stackoverflow
Solution 1 - JavascriptEstus FlaskView Answer on Stackoverflow
Solution 2 - JavascriptQwertyView Answer on Stackoverflow
Solution 3 - Javascriptford04View Answer on Stackoverflow
Solution 4 - JavascriptBrian BurnsView Answer on Stackoverflow
Solution 5 - JavascriptnullspaceView Answer on Stackoverflow
Solution 6 - JavascriptMinh KhaView Answer on Stackoverflow
Solution 7 - JavascriptTholleView Answer on Stackoverflow
Solution 8 - JavascriptGilCarvalhoDevView Answer on Stackoverflow
Solution 9 - JavascriptIdanView Answer on Stackoverflow
Solution 10 - JavascriptFergieView Answer on Stackoverflow
Solution 11 - JavascriptarielhadView Answer on Stackoverflow
Solution 12 - JavascriptwebNeatView Answer on Stackoverflow
Solution 13 - JavascriptcatamphetamineView Answer on Stackoverflow
Solution 14 - Javascriptthink-seriousView Answer on Stackoverflow
Solution 15 - JavascriptJanek OlszakView Answer on Stackoverflow
Solution 16 - JavascriptAlan C. S.View Answer on Stackoverflow
Solution 17 - JavascriptnghiepitView Answer on Stackoverflow
Solution 18 - Javascriptdavid_adlerView Answer on Stackoverflow