当一个 react 组件状态发生变化时,会调用 render 方法。因此,对于任何状态更改,都可以在渲染方法主体中执行操作。那么 setState 回调是否有特定的用例?
render()
中,它会在每次更新任何状态时运行,这可能不是您想要的。这也会使您的代码的可读性和逻辑性降低。
是的,因为 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
}
....
this.setState({
name:'value'
},() => {
console.log(this.state.name);
});
我想到的 1. 用例是一个 api
调用,它不应该进入渲染,因为它会在 each
状态更改时运行。并且 API 调用应该只在特殊状态更改时执行,而不是在 每个 渲染时执行。
changeSearchParams = (params) => {
this.setState({ params }, this.performSearch)
}
performSearch = () => {
API.search(this.state.params, (result) => {
this.setState({ result })
});
}
因此,对于任何状态更改,都可以在渲染方法主体中执行操作。
非常糟糕的做法,因为 render
方法应该是纯粹的,这意味着不应该执行任何操作、状态更改、api 调用,只需合成您的视图并返回它。应仅对某些事件执行操作。渲染不是一个事件,而是 componentDidMount
例如。
考虑 setState 调用
this.setState({ counter: this.state.counter + 1 })
主意
setState 可以在异步函数中调用
因此,您不能依赖 this
。如果上述调用是在异步函数中进行的,this
将引用该时间点的组件状态,但我们希望这会在 setState 调用或异步任务开始时引用状态内的属性。并且由于任务是异步调用,因此该属性可能已及时更改。因此使用 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 作为回调函数是个好主意。
我试图在这里用 codepen 解释它 CODE PEN
有时我们需要一个代码块,我们需要在 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
}
});
}
在渲染函数的 UI 块中也需要 enableModal 布尔值,这就是我在这里设置 setState 的原因,否则,可以只检查一次条件,然后调用 API 集或不调用。
if (this.title.length === 0) {
应该是this.state.title.length
,对吧?setState(state => state.title.length ? { titleError: "Title can't be blank" } : null)
,更改就会叠加。不需要双重渲染。