React - How to force a function component to render?

JavascriptReactjsReact Functional-Component

Javascript Problem Overview


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().

Javascript Solutions


Solution 1 - Javascript

 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.

Solution 2 - Javascript

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:

function App() {
  const [, updateState] = React.useState();
  const forceUpdate = React.useCallback(() => updateState({}), []);
  console.log("render");
  return (
    <div>
      <button onClick={forceUpdate}>Force Render</button>
    </div>
  );
}

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

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>
<div id="root"/>

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.

Solution 3 - Javascript

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();
  }

Solution 4 - Javascript

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

Solution 5 - Javascript

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.

Solution 6 - Javascript

Simplest way 

if you want to force a re-render, add a dummy state you can change to initiate a re-render.

const [rerender, setRerender] = useState(false);

...
setRerender(!rerender);     //whenever you want to re-render

And this will ensure a re-render, And you can call setRerender(!rerender) anywhere, whenever you want :)

Solution 7 - Javascript

Best approach - no excess variables re-created on each render:

const forceUpdateReducer = (i) => i + 1

export const useForceUpdate = () => {
  const [, forceUpdate] = useReducer(forceUpdateReducer, 0)
  return forceUpdate
}

Usage:

const forceUpdate = useForceUpdate()

forceUpdate()

Solution 8 - Javascript

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

Solution 9 - Javascript

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);

Solution 10 - Javascript

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(()=>{
    async function _ () {
      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)
    }
}

Solution 11 - Javascript

If you are using functional components with version < 16.8. One workaround would be to directly call the same function like

import React from 'react';

function MyComponent() {
    const forceUpdate = MyComponent();
    
    return (
        <div>
            <button onClick={forceUpdate}>
                Click to re-render
            </button>
        </div>
    );
}

But this will break if you were passing some prop to it. In my case i just passed the same props which I received to rerender function.

Solution 12 - Javascript

If you already have a state inside the function component and you don't want to alter it and requires a re-render you could fake a state update which will, in turn, re-render the component

const [items,setItems] = useState({
   name:'Your Name',
   status: 'Idle'
})
const reRender = () =>{
setItems((state) => [...state])
}

this will keep the state as it was and will make react into thinking the state has been updated

Solution 13 - Javascript

For me just updating the state didn't work. I am using a library with components and it looks like I can't force the component to update.

My approach is extending the ones above with conditional rendering. In my case, I want to resize my component when a value is changed.

//hook to force updating the component on specific change
const useUpdateOnChange = (change: unknown): boolean => {
  const [update, setUpdate] = useState(false);

  useEffect(() => {
    setUpdate(!update);
  }, [change]);

  useEffect(() => {
    if (!update) setUpdate(true);
  }, [update]);

  return update;
};

const MyComponent = () => {
  const [myState, setMyState] = useState();
  const update = useUpdateOnChange(myState);

  ...

  return (
    <div>
      ... ...
      {update && <LibraryComponent />}
    </div>
  );
};

You need to pass the value you want to track for change. The hook returns boolean which should be used for conditional rendering.

When the change value triggers the useEffect update goes to false which hides the component. After that the second useEffect is triggered and update goes true which makes the component visible again and this results in updating (resizing in my case).

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
QuestionGorakh NathView Question on Stackoverflow
Solution 1 - JavascriptYairoproView Answer on Stackoverflow
Solution 2 - JavascriptSagiv b.gView Answer on Stackoverflow
Solution 3 - JavascriptGramoteiView Answer on Stackoverflow
Solution 4 - JavascriptCharith JayasankaView Answer on Stackoverflow
Solution 5 - JavascriptAnkan-ZerobView Answer on Stackoverflow
Solution 6 - JavascriptAbrahamView Answer on Stackoverflow
Solution 7 - JavascriptAlexander DanilovView Answer on Stackoverflow
Solution 8 - JavascriptCharles GoodwinView Answer on Stackoverflow
Solution 9 - JavascriptManohar Reddy PoreddyView Answer on Stackoverflow
Solution 10 - Javascriptdanieltan95View Answer on Stackoverflow
Solution 11 - JavascriptNeel DsouzaView Answer on Stackoverflow
Solution 12 - JavascriptArshal_dView Answer on Stackoverflow
Solution 13 - JavascriptIoan StoianovView Answer on Stackoverflow