184

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

Prateek Gupta
  • 119
  • 2
  • 7
Gorakh Nath
  • 7,962
  • 12
  • 39
  • 66

13 Answers13

301

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.

Yairopro
  • 6,989
  • 5
  • 34
  • 45
  • 9
    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
  • Done. I changed the forceUpdate function to make it simpler, using a boolean. – Yairopro Jan 22 '19 at 10:07
  • 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
  • Learned 2 things today: You are correct and linter is sometimes fked and should not be trusted like a rule. – DanteTheSmith May 13 '19 at 13:45
  • 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
  • 4
    @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
  • What a lovely way to do it :) – vijayst Aug 26 '21 at 08:56
  • 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
  • 1
    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
67

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.

Enve
  • 6,298
  • 10
  • 38
  • 82
Sagiv b.g
  • 28,620
  • 8
  • 59
  • 91
  • ofc you can. change the props that comes to it – Marián Zeke Šedaj Oct 31 '17 at 11:52
  • 10
    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
  • 1
    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
58

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();
  }
Gramotei
  • 1,224
  • 14
  • 19
9

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
  • 2,745
  • 20
  • 35
  • 6
    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
8

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.
Ankan-Zerob
  • 3,210
  • 2
  • 17
  • 24
  • 1
    I have a case where i needed to disable the component updates and force it just when i want (is a moving ruler, that updates it's value every move and the updates caused a flickering behavior). So i decided to use classes on this component and i recommend that all components that need a deep control on the render behavior should be done in classes, because currently hooks do not provides a fine control over this behavior. (the current React version is 16.12) – Michael Wallace Dec 12 '19 at 02:28
  • I thought the same but, I wanted a quick fix so I used force update. – Charith Jayasanka Mar 29 '20 at 04:00
  • 2
    In the real world, there are uses for it. Nothing is ever perfect, and if you ever want to get software out the door, you better know how to makes things happen when someone else screws them up. – Brain2000 Aug 02 '20 at 02:42
8

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
  • 5,299
  • 1
  • 20
  • 39
3

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
  • 2,554
  • 1
  • 23
  • 28
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
  • 494
  • 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);
Manohar Reddy Poreddy
  • 21,015
  • 9
  • 137
  • 125
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
  • 714
  • 6
  • 11
  • 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
  • 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,138
  • 2
  • 11
  • 26
1

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
  • 76
  • 1
  • 6
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).