238

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

isherwood
  • 58,414
  • 16
  • 114
  • 157
Gorakh Nath
  • 9,140
  • 15
  • 46
  • 68

12 Answers12

400

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 state to force render
    // A function that increment  the previous state like here 
    // is better than directly setting `setValue(value + 1)`
}

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.

Yairopro
  • 9,084
  • 6
  • 44
  • 51
  • 15
    Nothing on that page has any information about using Hooks to call `forceUpdate`. – jdelman Dec 21 '18 at 14:47
  • but react hooks are not released yet. if you can modify component is not is better just to convert it into class? – skyboyer Dec 22 '18 at 19:25
  • 1
    For now, you're right it's better, because, even tough hooks are not released yet, you can still use it in beta. But once they are released, there is no reason class component will be better. Using hooks makes code cleaner than class component, as the video below in the reactconf shows. Anyway, the question is if this is possible. The answer now changes from "No" to "Yes" because of hooks. https://www.youtube.com/watch?v=wXLf18DsV-I – Yairopro Dec 22 '18 at 19:54
  • I t would be nice to have a small explanation under the code sample. How exactly is this working. Is this a custom hook? – Eric Bishard Jan 21 '19 at 14:23
  • Except linter warns you about RULES OF HOOKS. Hooks need to be TOP LEVEL, defined in React component, not under conditional or loop. This is not top level, this is definition outside of the component and kinda defies those rules. ES linter says -> React Hook "useState" is called in function "updateComponentState" which is neither a React function component or a custom React Hook function. Every rerender of this component expect to have its hooks defined and run in the same order as the 1st time. When you mix and mash this with other hooks I am afraid it will not play with other kids (hooks) – DanteTheSmith May 09 '19 at 12:17
  • 2
    Hi @DanteTheSmith. By "Top level", it means that hooks must not be called from inside a condition or loop, as you said. But I can tell you that you can call them from inside another function. And that means creating a custom hook. Dan Abramov, as he presents React hooks in the React conf, clearly demonstrate that this is the cleanest and best way to share logic between functional components: https://youtu.be/dpw9EHDh2bM?t=2753 – Yairopro May 10 '19 at 12:53
  • 1
    There's no need to toggle any state "to force render". You create a false impression that React "compares" prev and next state values to decide if it needs to re-render. While it definitely does not. – meandre Oct 15 '19 at 08:16
  • 5
    @meandre Yes it definitely compares. We are talking about the `useState` hook, not the class' `setState` which indeed doesn't make a comparaison (unless you implement shouldUpdate method). See the same demo I posted, but with a static value used for `setState`, it doesn't render again: https://codesandbox.io/s/determined-rubin-8598l – Yairopro Oct 15 '19 at 13:18
  • this only forces react to **internally** re-render but if nothing actually changed, the DOM will not change as well. What ***I am after*** is a **real** re-render where React does not decide if the DOM should be updated (using the virtual DOM) but force it to re-paint the whole component – vsync Jan 27 '21 at 22:28
  • Maybe what you're looking for is changing the key prop of your component, but it will unmount/remount the component thus reseting its state. It's an excellent way for pure components. – Yairopro Jan 28 '21 at 09:28
  • why not just useState({}) abd setState({}) – Eliav Louski Apr 26 '21 at 00:01
  • @EliavLouski just for education because it's easier to understand the concept by updating a primitive rather than by an object which needs a little background in pointers. – Yairopro Apr 28 '21 at 15:23
  • @Yairopro I couldn't get my sequential head around the "EDIT". With boolean, shouldn't it always run: `setValue(value => !value);` The setValue will always have new value that's different from old value, isn't it ? – somenickname Aug 10 '21 at 23:40
  • 1
    hi @somenickname. Yes but after calling `setValue(value => !value)`, React does not directly render. So if you call a 2nd time the same `setValue(value => !value)`, React recorded 2 mutations, each negates the state, which will reset the state at its original value (for boolean) `value => !value => !!value` (== value). Then react will compare if the state `value` is different from its last render, and only if so it will re-render the component. In our case it won't. See demo: https://codesandbox.io/s/mystifying-cohen-2jxux – Yairopro Aug 11 '21 at 13:24
  • @Yairopro Thanks a lot! Do you know why timeRendered increments by 2 when "updateOnce" (which updates on UI), and is also incrementing by 2 on "updateTwice" (though not updated on UI) ? – somenickname Aug 11 '21 at 15:43
  • @somenickname It's just a bug with codesandbox. Here's the same exemple with jsfiddle https://jsfiddle.net/3nbeat5u/4/ – Yairopro Aug 12 '21 at 16:18
  • @Yairopro This time it increments by 1 only, but I can still see it's internally incrementing by 1 with "updateTwice" (if you click updateTwice before updateOnce, you would see how it increments). Looks like it might have still "run" that functional component, just not updating the UI ? – somenickname Aug 13 '21 at 17:33
  • @somenickname yes it does look like so. – Yairopro Aug 16 '21 at 11:07
  • 1
    @somenickname It's not a bug with sandbox, it's because of the react `StrictMode` https://github.com/codesandbox/codesandbox-client/issues/5944#issuecomment-908506257 – Yairopro Sep 02 '21 at 08:15
  • 4
    an empty object will do the same trick – Snowmanzzz Nov 18 '21 at 10:58
  • 1
    @Snowmanzzz Of course, but (I think) the int is better just to learn the concept. It's just an educational choice. – Yairopro Nov 21 '21 at 07:48
  • Ultimately, as a last resort I've found it useful to use the default "key" property that every element in React has by default to re-render that element by changing the value passed to the key property: – vivanov Feb 03 '22 at 07:57
  • 1
    @MarcesEngel I wrote earlier in the comments that was just an educational choice. – Yairopro Feb 13 '22 at 06:27
  • I'm new to React and I don't understand why this component itself is rendered, if the state is "inside" the useForceUpdate hook. I thought that a component would render if it changed its state, not the state of a child component or dependent hook. Please, recommend me some documentation to better understand all the cases in which a component is rendered. – Antonito Jul 27 '22 at 01:20
  • useForceState is used as a function, not as sub component which would indeed render only the child. Here it's used as a function, a custom hook, which just wrap the call of useState @Antonito – Yairopro Jul 27 '22 at 11:01
88

Official FAQ now recommends this way if you really need to do it:

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

  function handleClick() {
    forceUpdate();
  }
vsync
  • 118,978
  • 58
  • 307
  • 400
Gramotei
  • 1,524
  • 14
  • 19
76

Update react v16.8 (16 Feb 2019 realease)

Since react 16.8 released with hooks, function components 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.

Idrizi.A
  • 9,819
  • 11
  • 47
  • 88
Sagiv b.g
  • 30,379
  • 9
  • 68
  • 99
  • 13
    that's not __forcing__ a re-render, that's just a normal render. when you want to __force__ rendering, it's usually a case when you want to run the render method when it wasn't designed to run, for example when there are no new `props` or `state` changes. you __can't__ force the render function as there is no `render`function on stateless components. stateless components doesn't `extends` `React.Component` they are just plain functions that returns `jsx`. – Sagiv b.g Oct 31 '17 at 12:04
  • 3
    Props for "when you need to force an update you're probably doing something wrong" - I knew that was the case, but this just prompted me to take one more good look at my useEffect hook. – Methodician Jul 30 '19 at 21:31
16

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

Abraham
  • 12,140
  • 4
  • 56
  • 92
11

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} />;
};
Charith Jayasanka
  • 4,033
  • 31
  • 42
  • 9
    To save you a click - `useForceUpdate` uses `useCallback` as mentioned in other answers. This lib is just a utility lib to save you few keystrokes. – asyncwait Feb 08 '20 at 04:45
5

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()
Alexander Danilov
  • 3,038
  • 1
  • 30
  • 35
2

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

Arshal_d
  • 116
  • 1
  • 6
1

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>
  )
}
Charles Goodwin
  • 584
  • 5
  • 8
1

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);
Eric Goerens
  • 67
  • 11
Manohar Reddy Poreddy
  • 25,399
  • 9
  • 157
  • 140
1

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)
    }
}
danieltan95
  • 810
  • 7
  • 14
  • It is never a good idea to use await in a React's built in hooks like useEffect. Also this code won't work because 'await' is not in an 'async' function in the first snippet. If you have some arbitrary loader or plugin that enables this, you should mention that because its not the default configuration. – Josh Merlino Mar 17 '21 at 22:54
  • 1
    updated it to include a trivial example of how to use async/await in useEffect. Unfortunately there are often very good usecases for using async/await in useEffect, no matter what your personal preferences are. – danieltan95 Mar 18 '21 at 08:13
1

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.

Neel Dsouza
  • 1,342
  • 4
  • 15
  • 33
0

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

Ioan Stoianov
  • 105
  • 10