当反应组件状态发生变化时,将调用render方法。因此,对于任何状态更改,可以在呈现方法主体中执行操作。那么setState回调是否有特定的用例?
答案 0 :(得分:176)
是的,因为setState
以asynchronous
的方式运作。这意味着在调用setState
后,this.state
变量不会立即更改。因此,如果要在状态变量上设置状态后立即执行操作然后返回结果,则回调将非常有用
考虑以下示例
....
changeTitle: function changeTitle (event) {
this.setState({ title: event.target.value });
this.validateTitle();
},
validateTitle: function validateTitle () {
if (this.state.title.length === 0) {
this.setState({ titleError: "Title can't be blank" });
}
},
....
上述代码可能无法按预期工作,因为title
变量在对其执行验证之前可能没有发生变异。现在您可能想知道我们可以在render()
函数本身中执行验证,但如果我们可以在changeTitle函数本身处理它,那将会更好,更清晰,因为这会使您的代码更有条理和可理解
在这种情况下,回调很有用
....
changeTitle: function changeTitle (event) {
this.setState({ title: event.target.value }, function() {
this.validateTitle();
});
},
validateTitle: function validateTitle () {
if (this.state.title.length === 0) {
this.setState({ titleError: "Title can't be blank" });
}
},
....
另一个例子是当你想要dispatch
和状态改变时的动作。你会想要在回调而不是render()
中进行,因为每次重新渲染都会调用它,因此在你需要回调的情况下可能会有很多这样的场景。
另一种情况是API Call
当您需要根据特定的状态更改进行API调用时,可能会出现这种情况,如果您在render方法中执行此操作,则会在每次渲染onState
更改时调用它,或者因为某些Prop传递下来改为Child Component
。
在这种情况下,您可能希望使用setState callback
将更新后的状态值传递给API调用
....
changeTitle: function (event) {
this.setState({ title: event.target.value }, () => this.APICallFunction());
},
APICallFunction: function () {
// Call API with the updated value
}
....
答案 1 :(得分:38)
我想到的1. usecase是一个api
调用,它应该进入渲染,因为它将运行each
状态更改。 API调用应仅在特殊状态更改时执行,而不是在每个渲染时执行。
changeSearchParams = (params) => {
this.setState({ params }, this.performSearch)
}
performSearch = () => {
API.search(this.state.params, (result) => {
this.setState({ result })
});
}
因此,对于任何状态更改,都可以在渲染方法体中执行操作。
非常糟糕的做法,因为render
- 方法应该是纯粹的,这意味着不应该执行任何操作,状态更改,api调用,只需合成视图并将其返回。应仅对某些事件执行操作。渲染不是一个事件,而是componentDidMount
例如。
答案 2 :(得分:22)
this.setState({
name:'value'
},() => {
console.log(this.state.name);
});
答案 3 :(得分:18)
考虑setState调用
this.setState({ counter: this.state.counter + 1 })
IDEA 1
可以在异步函数中调用setState
所以你不能依赖this
。如果上面的调用是在异步函数this
内进行的,那么将引用该时间点的组件状态,但我们希望在setState调用或async任务开始时引用状态。因为任务是异步调用,因此财产可能已经及时改变。因此,使用this
关键字来引用状态的某些属性是不可靠的,因此我们使用其参数为previousState和props的回调函数,这意味着当异步任务完成时,是时候使用setState调用更新状态prevState将引用当setState尚未启动时立即声明。确保nextState不会被破坏的可靠性。
错误的代码:会导致数据损坏
this.setState(
{counter:this.state.counter+1}
);
使用具有回调函数的setState更正代码:
this.setState(
(prevState,props)=>{
return {counter:prevState.counter+1};
}
);
因此,每当我们需要根据属性刚刚提供的值将当前状态更新为下一状态并且所有这些都以异步方式发生时,最好使用setState作为回调函数。
IDEA 2
setState调用可能是async
本身bcz React 可能会尝试将两个或多个setState调用组合在一起以进行性能改进。 无论如何那是不可靠的。假设在 t = 0 处触发了两个setState调用。他们在调用之前都指的是相同的状态(state_0),作为异步我们不能依赖哪个将首先结束。假设一个呼叫可能导致 state_1 ,因为其中一个呼叫结束。其他调用状态指的是初始状态(state_0)可能会导致 state_3 。这可能会导致国家及其数据的腐败。使用回调函数,其中回调函数的参数是prevState,props。它确保如果其中一个首先结束通向 state_1 ,则下一个setState将始终将prevState称为初始状态。因此,始终确保数据不会被破坏。由于同时调用setState,因此数据损坏的可能性非常小。但是如果我们需要我们的下一个状态依赖于prevState,那么总是使用回调。
我试图在codepen中解释它 CODE PEN
答案 4 :(得分:0)
有时候,我们需要一个代码块,在其中我们需要在setState之后执行一些操作,以确保状态得到更新。那就是setState回调起作用的地方
例如,在一种情况下,我需要为20个客户中的2个客户启用一个模式,对于我们启用了该模式的客户,需要一段时间来进行API调用,因此看起来像这样>
async componentDidMount() {
const appConfig = getCustomerConfig();
this.setState({enableModal: appConfig?.enableFeatures?.paymentModal }, async
()=>{
if(this.state.enableModal){
//make some API call for data needed in poput
}
});
}
enableModal布尔值也需要在render函数的UI块中使用,这就是为什么我在这里执行setState的原因,否则,只需检查一次条件就可以调用或不调用API。