[javascript] React - How to force a function component to render?

I have a function component, and I want to force it to re-render.

How can I do so?
Since there's no instance this, I cannot call this.forceUpdate().

This question is related to javascript reactjs

The answer is


You can now, using React hooks

Using react hooks, you can now call useState() in your function component.

useState() will return an array of 2 things:

  1. A value, representing the current state.
  2. Its setter. Use it to update the value.

Updating the value by its setter will force your function component to re-render,
just like forceUpdate does:

import React, { useState } from 'react';

//create your forceUpdate hook
function useForceUpdate(){
    const [value, setValue] = useState(0); // integer state
    return () => setValue(value => value + 1); // update the state to force render
}

function MyComponent() {
    // call your hook here
    const forceUpdate = useForceUpdate();
    
    return (
        <div>
            {/*Clicking on the button will force to re-render like force update does */}
            <button onClick={forceUpdate}>
                Click to re-render
            </button>
        </div>
    );
}

You can find a demo here.

The component above uses a custom hook function (useForceUpdate) which uses the react state hook useState. It increments the component's state's value and thus tells React to re-render the component.

EDIT

In an old version of this answer, the snippet used a boolean value, and toggled it in forceUpdate(). Now that I've edited my answer, the snippet use a number rather than a boolean.

Why ? (you would ask me)

Because once it happened to me that my forceUpdate() was called twice subsequently from 2 different events, and thus it was reseting the boolean value at its original state, and the component never rendered.

This is because in the useState's setter (setValue here), React compare the previous state with the new one, and render only if the state is different.


None of these gave me a satisfactory answer so in the end I got what I wanted with the key prop, useRef and some random id generator like shortid.

Basically, I wanted some chat application to play itself out the first time someone opens the app. So, I needed full control over when and what the answers are updated with the ease of async await.

Example code:

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

// ... your JSX functional component, import shortid somewhere

const [render, rerender] = useState(shortid.generate())

const messageList = useRef([
    new Message({id: 1, message: "Hi, let's get started!"})
])

useEffect(()=>{
    await sleep(500)
    messageList.current.push(new Message({id: 1, message: "What's your name?"}))
    // ... more stuff
    // now trigger the update
    rerender(shortid.generate())
}, [])

// only the component with the right render key will update itself, the others will stay as is and won't rerender.
return <div key={render}>{messageList.current}</div> 

In fact this also allowed me to roll something like a chat message with a rolling .

const waitChat = async (ms) => {
    let text = "."
    for (let i = 0; i < ms; i += 200) {
        if (messageList.current[messageList.current.length - 1].id === 100) {
            messageList.current = messageList.current.filter(({id}) => id !== 100)
        }
        messageList.current.push(new Message({
            id: 100,
            message: text
        }))
        if (text.length === 3) {
            text = "."
        } else {
            text += "."
        }
        rerender(shortid.generate())
        await sleep(200)
    }
    if (messageList.current[messageList.current.length - 1].id === 100) {
        messageList.current = messageList.current.filter(({id}) => id !== 100)
    }
}

Update react v16.8 (16 Feb 2019 realease)

Since react 16.8 released with hooks, function components are now have the ability to hold persistent state. With that ability you can now mimic a forceUpdate:

_x000D_
_x000D_
function App() {_x000D_
  const [, updateState] = React.useState();_x000D_
  const forceUpdate = React.useCallback(() => updateState({}), []);_x000D_
  console.log("render");_x000D_
  return (_x000D_
    <div>_x000D_
      <button onClick={forceUpdate}>Force Render</button>_x000D_
    </div>_x000D_
  );_x000D_
}_x000D_
_x000D_
const rootElement = document.getElementById("root");_x000D_
ReactDOM.render(<App />, rootElement);
_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>_x000D_
<div id="root"/>
_x000D_
_x000D_
_x000D_

Note that this approach should be re-considered and in most cases when you need to force an update you probably doing something wrong.


Before react 16.8.0

No you can't, State-Less function components are just normal functions that returns jsx, you don't have any access to the React life cycle methods as you are not extending from the React.Component.

Think of function-component as the render method part of the class components.


This can be done without explicitly using hooks provided you add a prop to your component and a state to the stateless component's parent component:

const ParentComponent = props => {
  const [updateNow, setUpdateNow] = useState(true)

  const updateFunc = () => {
    setUpdateNow(!updateNow)
  }

  const MyComponent = props => {
    return (<div> .... </div>)
  }

  const MyButtonComponent = props => {
    return (<div> <input type="button" onClick={props.updateFunc} />.... </div>)
  }

  return (
    <div> 
      <MyComponent updateMe={updateNow} />
      <MyButtonComponent updateFunc={updateFunc}/>
    </div>
  )
}

I used a third party library called use-force-update to force render my react functional components. Worked like charm. Just use import the package in your project and use like this.

import useForceUpdate from 'use-force-update';

const MyButton = () => {

  const forceUpdate = useForceUpdate();

  const handleClick = () => {
    alert('I will re-render now.');
    forceUpdate();
  };

  return <button onClick={handleClick} />;
};

Official FAQ ( https://reactjs.org/docs/hooks-faq.html#is-there-something-like-forceupdate ) now recommends this way if you really need to do it:

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

  function handleClick() {
    forceUpdate();
  }

The accepted answer is good. Just to make it easier to understand.

Example component:

export default function MyComponent(props) {

    const [updateView, setUpdateView] = useState(0);

    return (
        <>
            <span style={{ display: "none" }}>{updateView}</span>
        </>
    );
}

To force re-rendering call the code below:

setUpdateView((updateView) => ++updateView);

Disclaimer: NOT AN ANSWER TO THE PROBLEM.

Leaving an Important note here:

If you are trying to forceupdate a stateless component, chances are there is something wrong with your design.

Consider the following cases:

  1. Pass a setter (setState) to a child component that can change state and cause the parent component to re-render.
  2. Consider lifting state up
  3. Consider putting that state in your Redux store, that can automatically force a re-render on connected components.