通过setState回调使用componentDidUpdate有什么好处?

为什么在React组件中(如果需要同步setState行为)componentDidUpdate建议在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回调更适合使用?

回答:

为什么componentDidUpdatesetState回调函数上推荐使用更多?

1.逻辑一致

在使用callback参数时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()重新呈现组件后,执行callback参数。但是,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()也可以打印新值。由于我们只有一个渲染发生,因此它只执行一次,并打印value 42

如果您希望与批处理更新保持一致,通常使用起来会容易得多componentDidMount()

2.1。何时分批进行?

没关系

批处理是一种 优化 ,因此,您永远不应依赖已发生或未发生的批处理。未来版本的React可能会在不同情况下执行或多或少的批处理。

但是,如果您必须知道,在当前版本的React(16.8.x)中,如果React可以完全控制执行,则批处理将在异步用户事件处理程序(例如onclick)中进行,

有时在 生命周期方法中进行。所有其他上下文从不使用批处理。

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,但即使是这样,它不会正确由于批处理工作。

杂项

由于setState是异步的,因此我在考虑使用setState回调函数(第二个参数)来确保状态更新后执行代码,这与.then()promise

类似。

回调setState()相当 的工作方式相同的承诺做的,所以它可能是最好分开你的知识。

特别是如果我需要在后续setState调用之间重新渲染。

为什么您需要在两次setState()调用之间重新渲染组件?

我能想象的唯一原因是父组件是否依赖于子DOM元素的某些信息(例如其宽度或高度),并且父组件基于这些值在子组件上设置了一些道具。

在您的示例中,您调用this.props.functionFromParentComponent(),它返回一个值,然后将其用于计算某些状态。

首先,应该避免派生状态,因为记忆是一个更好的选择。但是即使如此,为什么不让父母直接将值作为道具传递呢?然后,您至少可以计算中的状态值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()并不表示有关状态无法正确更新的任何信息。该代码应按预期工作。

以上是 通过setState回调使用componentDidUpdate有什么好处? 的全部内容, 来源链接: utcz.com/qa/421294.html

回到顶部