乐闻世界logo
搜索文章和话题

React 在不使用 setState 的情况下实现组件的强制刷新?

9 个月前提问
5 个月前修改
浏览次数114

6个答案

1
2
3
4
5
6

在React中,通常我们通过调用setState来通知组件需要更新其状态,并触发重新渲染。不过,如果需要在不直接调用setState的情况下强制组件重新渲染,可以使用下面几种方法:

  1. 使用forceUpdate()方法 React类组件中的forceUpdate()方法会使组件跳过shouldComponentUpdate,直接触发一个重新渲染。

    jsx
    class MyComponent extends React.Component { someMethod() { // ... 执行某些操作后,需要强制重新渲染 this.forceUpdate(); } render() { // render logic } }

    这种方式不推荐频繁使用,因为它绕过了React的正常更新流程(如shouldComponentUpdate生命周期方法),可能导致性能问题。

  2. 使用Hooks中的一个小技巧 在函数组件中,我们可以使用useState和一个更新函数来强制重新渲染。

    jsx
    import { useState, useCallback } from 'react'; function MyComponent() { const [, updateState] = useState(); const forceUpdate = useCallback(() => updateState({}), []); function handleSomeAction() { // ... 执行某些操作后,需要强制重新渲染 forceUpdate(); } return ( // render logic ); }

    通过更改状态来触发重新渲染,即使状态值没有实际改变。

  3. 使用Key改变 通过改变组件的key属性,可以让React卸载当前组件并且装载一个新的组件实例。

    jsx
    function MyParentComponent() { const [key, setKey] = useState(0); function forceRender() { setKey(prevKey => prevKey + 1); } return <MyComponent key={key} />; }

    key发生变化时,React将会认为是不同的组件,并且进行重新装载。这会导致组件的状态被重置,因此该方法适用于没有状态或者可以丢弃状态的组件。

需要注意的是,不推荐在常规开发中绕过React的正常更新流程来强制渲染,这样做通常会违背React声明式编程的理念,可能造成不可预见的问题。在大部分情况下,合理使用state和props来控制组件的渲染会更加符合React的设计哲学。强制更新通常用于与外部库交互或者处理一些特殊的副作用。

2024年6月29日 12:07 回复

forceUpdate should be avoided because it deviates from a React mindset. The React docs cite an example of when forceUpdate might be used:

By default, when your component's state or props change, your component will re-render. However, if these change implicitly (eg: data deep within an object changes without changing the object itself) or if your render() method depends on some other data, you can tell React that it needs to re-run render() by calling forceUpdate().

However, I'd like to propose the idea that even with deeply nested objects, forceUpdate is unnecessary. By using an immutable data source tracking changes becomes cheap; a change will always result in a new object so we only need to check if the reference to the object has changed. You can use the library Immutable JS to implement immutable data objects into your app.

Normally you should try to avoid all uses of forceUpdate() and only read from this.props and this.state in render(). This makes your component "pure" and your application much simpler and more efficient.forceUpdate()

Changing the key of the element you want re-rendered will work. Set the key prop on your element via state and then when you want to update set state to have a new key.

shell
<Element key={this.state.key} />

Then a change occurs and you reset the key

shell
this.setState({ key: Math.random() });

I want to note that this will replace the element that the key is changing on. An example of where this could be useful is when you have a file input field that you would like to reset after an image upload.

While the true answer to the OP's question would be forceUpdate() I have found this solution helpful in different situations. I also want to note that if you find yourself using forceUpdate you may want to review your code and see if there is another way to do things.

NOTE 1-9-2019:

The above (changing the key) will completely replace the element. If you find yourself updating the key to make changes happen you probably have an issue somewhere else in your code. Using Math.random() in key will re-create the element with each render. I would NOT recommend updating the key like this as react uses the key to determine the best way to re-render things.

2024年6月29日 12:07 回复

In 2021 and 2022, this is the official way to forceUpdate a React Functional Component.

shell
const [, forceUpdate] = useReducer(x => x + 1, 0); function handleClick() { forceUpdate(); }

I know the OP is for a class component. But the question was asked in 2015 and now that hooks are available, many may search for forceUpdate in functional components. This little bit is for them.

Edit 18th Apr 2022

It's usually bad practice to force update your components.

A few reasons that can cause the need to use force updates.

  • Not using state variables where you have to - local, redux, context.
  • The field from the state object you are trying to access and expecting to update/change is too deeply nested in objects or arrays. Even Redux advises to maintain flat objects or arrays. If only one field value changes in a complex object, React may not figure out that the state object has changed, thus it does not update the component. Keep your state flat and simple.
  • The key on your list items, as mentioned in another answer. In fact, this can cause other unexpected behaviors as well. I've seen lists where items are repeatedly rendered (duplicates) because the keys aren't identical or the keys are just missing altogether. Always request the backend team to send unique ids everywhere possible! Avoid using array indexes for keys. Do not try to create unique ids on the front-end by using nanoid, uuid or random. Because ids created using above methods change each time the component updates (keys provided to a list need to be static and the same on each render). Creating unique ids is usually a backend concern. Try your best to not bring that requirement to the front-end. The front-end's responsibility is only to paint what data the backend returns and not create data on the fly.
  • If your useEffect, useCallback dependency arrays do not have the proper values set. Use ESLint to help you with this one! Also, this is one of the biggest causes for memory leaks in React. Clean up your state and event listeners in the return callback to avoid memory leaks. Because such memory leaks are awfully difficult to debug.
  • Always keep an eye on the console. It's your best friend at work. Solving warning and errors that show up in the console can fix a whole lot of nasty things - bugs and issues that you aren't even aware off.

A few things I can remember that I did wrong. In case it helps..

2024年6月29日 12:07 回复

Actually, forceUpdate() is the only correct solution as setState() might not trigger a re-render if additional logic is implemented in shouldComponentUpdate() or when it simply returns false.

forceUpdate()

Calling forceUpdate() will cause render() to be called on the component, skipping shouldComponentUpdate(). more...

setState()

setState() will always trigger a re-render unless conditional rendering logic is implemented in shouldComponentUpdate(). more...


forceUpdate() can be called from within your component by this.forceUpdate()


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


BTW: Are you mutating state or your nested properties don't propagate?

2024年6月29日 12:07 回复

I Avoided forceUpdate by doing following

WRONG WAY : do not use index as key

shell
this.state.rows.map((item, index) => <MyComponent cell={item} key={index} /> )

CORRECT WAY : Use data id as key, it can be some guid etc

shell
this.state.rows.map((item) => <MyComponent item={item} key={item.id} /> )

so by doing such code improvement your component will be UNIQUE and render naturally

2024年6月29日 12:07 回复

你的答案