gpt4 book ai didi

javascript - 与 setState 回调相比,使用 componentDidUpdate 有什么优势?

转载 作者:搜寻专家 更新时间:2023-11-01 04:12:16 26 4
gpt4 key购买 nike

为什么使用 componentDidUpdate更多推荐超过setState React 组件中的回调函数(可选的第二个参数)(如果需要同步 setState 行为)?

由于setState是异步的,我正在考虑使用 setState回调函数(第二个参数)确保代码在状态更新后执行,类似于 then()为了 promise 。特别是如果我需要在后续 setState 之间重新渲染来电。

然而,官方的 React Docs 说“setState() 的第二个参数是一个可选的回调函数,一旦 setState 完成并重新渲染组件就会执行。一般我们建议使用 componentDidUpdate() 来代替这种逻辑。”
这就是他们在那里所说的一切,所以看起来有点模糊。我想知道是否有更具体的原因建议不要使用它?如果可以的话,我会问 React 的人自己。

如果我希望按顺序执行多个 setState 调用,则 setState 回调在代码组织方面似乎比 componentDidUpdate 更好 - 回调代码是在 setState 调用中定义的。如果我使用 componentDidUpdate 我必须检查相关的状态变量是否发生了变化,并在那里定义后续代码,这不太容易跟踪。此外,在包含 setState 调用的函数中定义的变量将超出范围,除非我也将它们放入状态。

以下示例可能会显示何时使用 componentDidUpdate 可能会很棘手:

private functionInComponent = () => {
let someVariableBeforeSetStateCall;

... // operations done on someVariableBeforeSetStateCall, etc.

this.setState(
{ firstVariable: firstValue, }, //firstVariable may or may not have been changed
() => {
let secondVariable = this.props.functionFromParentComponent();
secondVariable += someVariableBeforeSetStateCall;
this.setState({ secondVariable: secondValue });
}
);
}

对比
public componentDidUpdate(prevProps. prevState) {
if (prevState.firstVariableWasSet !== this.state.firstVariableWasSet) {
let secondVariable = this.props.functionFromParentComponent();
secondVariable += this.state.someVariableBeforeSetStateCall;
this.setState({
secondVariable: secondValue,
firstVariableWasSet: false,
});
}
}

private functionInComponent = () => {
let someVariableBeforeSetStateCall = this.state.someVariableBeforeSetStateCall;

... // operations done on someVariableBeforeSetStateCall, etc.

this.setState({
firstVariable: firstValue,
someVariableBeforeSetStateCall: someVariableBeforeSetStateCall,
firstVariableWasSet: true });
//firstVariable may or may not have been changed via input,
//now someVariableBeforeSetStateCall may or may not get updated at the same time
//as firstVariableWasSet or firstVariable due to async nature of setState
}


另外,除了通常推荐使用 componentDidUpdate 之外,在什么情况下 setState 回调更适合使用?

最佳答案

Why is using componentDidUpdate more recommended over the setState callback function?



1. 一致的逻辑

使用 setState() 的回调参数时,您可能有两次单独调用 setState()在更新相同状态的不同地方,您必须记住在两个地方使用相同的回调。

一个常见的例子是每当状态改变时调用第三方服务:

private method1(value) {
this.setState({ value }, () => {
SomeAPI.gotNewValue(this.state.value);
});
}

private method2(newval) {
this.setState({ value }); // forgot callback?
}

这可能是一个逻辑错误,因为您可能想在值更改时调用该服务。

这就是为什么 componentDidUpdate()被推荐:

public componentDidUpdate(prevProps, prevState) {
if (this.state.value !== prevState.value) {
SomeAPI.gotNewValue(this.state.value);
}
}

private method1(value) {
this.setState({ value });
}

private method2(newval) {
this.setState({ value });
}

这样,保证在状态更新时调用服务。

此外,状态可以从外部代码(例如 Redux)更新,您将没有机会为这些外部更新添加回调。

2.批量更新
setState() 的回调参数在组件重新渲染后执行。但是,多次调用 setState()由于批处理,不保证会导致多次渲染。

考虑这个组件:

class Foo extends React.Component {
constructor(props) {
super(props);
this.state = { value: 0 };
}

componentDidUpdate(prevProps, prevState) {
console.log('componentDidUpdate: ' + this.state.value);
}

onClick = () => {
this.setState(
{ value: 7 },
() => console.log('onClick: ' + this.state.value));
this.setState(
{ value: 42 },
() => console.log('onClick: ' + this.state.value));
}

render() {
return <button onClick={this.onClick}>{this.state.value}</button>;
}
}

我们有两个 setState()调用 onClick()处理程序,每个都只是将新的状态值打印到控制台。

您可能期望 onClick()打印值 7然后 42 .但实际上,它会打印 42两次!这是因为两个 setState()调用被批处理在一起,并且只会导致一次渲染发生。

另外,我们有一个 componentDidUpdate()它还打印新值。由于我们只发生了一次渲染,它只执行一次,并打印值 42 .

如果您希望与批量更新保持一致,使用 componentDidMount() 通常要容易得多。 .

2.1。什么时候发生批处理?

没关系。

批处理是一种优化,因此您不应该依赖批处理发生或不发生。 React 的 future 版本可能会在不同的场景中执行或多或少的批处理。

但是,如果您必须知道,在当前版本的 React (16.8.x) 中,如果 React 可以完全控制执行,批处理会发生在异步用户事件处理程序(例如 onclick )中,有时甚至是生命周期方法。所有其他上下文从不使用批处理。

有关更多信息,请参阅此答案: https://stackoverflow.com/a/48610973/640397

3. 什么时候用 setState比较好打回来?

当外部代码需要等待状态更新时,您应该使用 setState回调而不是 componentDidUpdate , 并将其包装在一个 promise 中。

例如,假设我们有一个 Child看起来像这样的组件:
interface IProps {
onClick: () => Promise<void>;
}

class Child extends React.Component<IProps> {

private async click() {
await this.props.onClick();

console.log('Parent notified of click');
}

render() {
return <button onClick={this.click}>click me</button>;
}
}

我们有一个 Parent单击子项时必须更新某些状态的组件:
class Parent extends React.Component {
constructor(props) {
super(props);

this.state = { clicked: false };
}

private setClicked = (): Promise<void> => {
return new Promise((resolve) => this.setState({ clicked: true }, resolve));
}

render() {
return <Child onClick={this.setClicked} />;
}
}

setClicked ,我们必须创建一个 Promise返回子节点,唯一的方法是将回调传递给 setState .

无法创建 PromisecomponentDidUpdate ,但即使是这样,由于批处理,它也无法正常工作。

杂项。

Since setState is asynchronous, I was thinking about using the setState callback function (2nd argument) to ensure that code is executed after state has been updated, similar to .then() for promises.


setState() 的回调与 Promise 的工作方式不同,因此最好将您的知识分开。

Especially if I need a re-render in between subsequent setState calls.



为什么需要在 setState() 之间重新渲染组件?电话?

我能想象的唯一原因是父组件是否依赖于子 DOM 元素的某些信息,例如它的宽度或高度,并且父组件根据这些值在子组件上设置一些 Prop 。

在您的示例中,您调用 this.props.functionFromParentComponent() ,它返回一个值,然后您可以使用该值来计算某些状态。

首先,应该避免派生状态,因为内存是一个更好的选择。但即便如此,为什么不让父级直接将值作为 Prop 传递下去呢?然后你至少可以计算 getDerivedStateFromProps() 中的状态值.

  //firstVariable may or may not have been changed, 
//now someVariableBeforeSetStateCall may or may not get updated at the same time
//as firstVariableWasSet or firstVariable due to async nature of setState

这些评论对我来说没有多大意义。 setState() 的异步特性并不意味着状态没有得到正确更新。代码应该按预期工作。

关于javascript - 与 setState 回调相比,使用 componentDidUpdate 有什么优势?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56501409/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com