我有一个外部(组件),可观察对象,我想监听的变化。当对象更新时,它会发出更改事件,然后我希望在检测到任何更改时重新呈现组件。

使用顶级React。渲染这是可能的,但在组件中它不起作用(这是有意义的,因为渲染方法只返回一个对象)。

下面是一个代码示例:

export default class MyComponent extends React.Component {

  handleButtonClick() {
    this.render();
  }

  render() {
    return (
      <div>
        {Math.random()}
        <button onClick={this.handleButtonClick.bind(this)}>
          Click me
        </button>
      </div>
    )
  }
}

在内部单击按钮会调用this.render(),但这并不是真正导致呈现发生的原因(您可以在操作中看到这一点,因为由{Math.random()}创建的文本没有改变)。但是,如果我简单地调用this.setState()而不是this.render(),它就可以正常工作。

所以我想我的问题是:React组件需要有状态才能渲染吗?是否有一种方法可以在不改变状态的情况下强制组件按需更新?


当前回答

应该避免使用forceUpdate,因为它偏离了React的思维模式。React文档引用了一个何时使用forceUpdate的例子:

默认情况下,当组件的状态或道具改变时,组件将重新呈现。然而,如果这些隐式变化(例如:对象内部的深层数据变化而不改变对象本身),或者如果你的render()方法依赖于一些其他数据,你可以通过调用forceUpdate()告诉React它需要重新运行render()。

然而,我想提出这样的观点:即使对于嵌套很深的对象,forceUpdate也是不必要的。通过使用不可变数据源跟踪更改变得便宜;更改总是会产生一个新对象,因此我们只需要检查对对象的引用是否已更改。你可以使用Immutable JS库将不可变数据对象实现到你的应用程序中。

通常情况下,你应该尽量避免使用forceUpdate(),只从这个中读取。道具和这个。render()中的状态。这使得你的组件“纯粹”,你的应用程序更简单、更高效。

改变你想要重新渲染的元素的键也可以。通过state在元素上设置键道具,然后当你想更新Set state时有一个新的键。

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

然后发生了变化,您重置了密钥

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

我要注意的是,这将取代键改变的元素。这可能有用的一个例子是,当您有一个文件输入字段,您希望在图像上传后重置。

虽然OP问题的真正答案是forceUpdate(),但我发现这个解决方案在不同的情况下都很有用。我还想指出的是,如果你发现自己使用了forceUpdate,你可能需要检查你的代码,看看是否有另一种方法来做事情。

注意1-9-2019:

以上(改变键)将完全替换元素。如果您发现自己正在更新键来进行更改,那么您的代码中的其他地方可能存在问题。在key中使用Math.random()将在每次渲染时重新创建元素。我不建议像这样更新键,因为react使用键来确定重新渲染事物的最佳方式。

其他回答

应该避免使用forceUpdate,因为它偏离了React的思维模式。React文档引用了一个何时使用forceUpdate的例子:

默认情况下,当组件的状态或道具改变时,组件将重新呈现。然而,如果这些隐式变化(例如:对象内部的深层数据变化而不改变对象本身),或者如果你的render()方法依赖于一些其他数据,你可以通过调用forceUpdate()告诉React它需要重新运行render()。

然而,我想提出这样的观点:即使对于嵌套很深的对象,forceUpdate也是不必要的。通过使用不可变数据源跟踪更改变得便宜;更改总是会产生一个新对象,因此我们只需要检查对对象的引用是否已更改。你可以使用Immutable JS库将不可变数据对象实现到你的应用程序中。

通常情况下,你应该尽量避免使用forceUpdate(),只从这个中读取。道具和这个。render()中的状态。这使得你的组件“纯粹”,你的应用程序更简单、更高效。

改变你想要重新渲染的元素的键也可以。通过state在元素上设置键道具,然后当你想更新Set state时有一个新的键。

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

然后发生了变化,您重置了密钥

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

我要注意的是,这将取代键改变的元素。这可能有用的一个例子是,当您有一个文件输入字段,您希望在图像上传后重置。

虽然OP问题的真正答案是forceUpdate(),但我发现这个解决方案在不同的情况下都很有用。我还想指出的是,如果你发现自己使用了forceUpdate,你可能需要检查你的代码,看看是否有另一种方法来做事情。

注意1-9-2019:

以上(改变键)将完全替换元素。如果您发现自己正在更新键来进行更改,那么您的代码中的其他地方可能存在问题。在key中使用Math.random()将在每次渲染时重新创建元素。我不建议像这样更新键,因为react使用键来确定重新渲染事物的最佳方式。

你可以使用forceUpdate()来了解更多细节。

当你想要两个React组件进行通信时,它们不受关系(父子关系)的约束,建议使用Flux或类似的架构。

您要做的是监听可观察组件存储的变化,该存储保存模型及其接口,并将导致呈现变化的数据保存为MyComponent中的状态。当存储推送新数据时,更改组件的状态,这会自动触发呈现。

通常你应该尽量避免使用forceUpdate()。从文档中可以看到:

通常情况下,你应该尽量避免使用forceUpdate(),只从这个中读取。道具和这个。render()中的状态。这使您的应用程序更加简单和高效

为了完整性,你也可以在功能组件中实现:

const [, updateState] = useState();
const forceUpdate = useCallback(() => updateState({}), []);
// ...
forceUpdate();

或者,作为一个可重复使用的钩子:

const useForceUpdate = () => {
  const [, updateState] = useState();
  return useCallback(() => updateState({}), []);
}
// const forceUpdate = useForceUpdate();

参见:https://stackoverflow.com/a/53215514/2692307

请注意,使用强制更新机制仍然是不好的做法,因为它违背了反应的心态,所以如果可能的话仍然应该避免。

在2021年和2022年,这将是强制更新React功能组件的官方方式。

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

  function handleClick() {
    forceUpdate();
  }

我知道OP是一个类组件。但这个问题是在2015年提出的,现在钩子可用,许多人可能会在功能组件中搜索forceUpdate。这一点是给他们的。

编辑2022年4月18日

强制更新组件通常是不好的做法。

有几个原因可能导致需要使用强制更新。

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.

我记得我做错的几件事。万一有用的话…