通过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回调更适合使用?
回答:
为什么
componentDidUpdate
在setState
回调函数上推荐使用更多?
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
。
这是不可能创建此Promise
在componentDidUpdate
,但即使是这样,它不会正确由于批处理工作。
杂项
由于
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