提问人:physicsboy 提问时间:1/11/2018 最后编辑:Shubham Khatriphysicsboy 更新时间:10/9/2020 访问量:29541
何时使用函数式 setState
When to use functional setState
问:
在过去的几天里,我一直在学习 React,查看了一些关于编写不同元素的不同方式的教程和解释。但是,有一个我最好奇的函数 - 更新/覆盖组件属性的函数。setState
state
例如,假设我有一个包含以下内容的类:
class Photos extends React.Component {
constructor() {
super()
state = {
pictures: []
}
}
componentDidMount() {
// This is where the fetch and setState will occur (see below)
}
render() {
return {
<div className="container">
{this.state.pictures}
</div>
}
}
}
在此示例中,我从 API 获取图像。
鉴于我已经执行了此函数的获取、映射和返回 - 然后我将使用 API 调用中获得的结果更新状态数组。pictures: []
我的问题源于我看到的关于如何更新/覆盖图片状态属性的不同方法。
我看到它以 2 种不同的方式编写:
1)这似乎是一个非常简单易读的方法
this.setState({pictures: pics})
2)这更复杂,但我看到它被描述为一种更安全的方法
this.setState(prevState => ({
pictures: prevState.pictures.concat(pics)
}))
有人可以解释一下使用其中任何一个的优点吗?我希望将来与代码保持一致,处理道具和状态等,因此最通用的方法当然是首选。
答:
TL;DR:功能主要有助于在短时间内触发多个 s 时期望正确的状态更新,而按照传统,协调并可能导致意外状态。setState
setState
setState
请查看这篇关于函数式 setState 的精彩文章,以获得清晰的理解
这是工作演示
首先,您尝试在每种情况下做不同的事情,您在一种情况下分配图片并在另一种情况下连接图片。
假设 this.state.pictures 包含和 pics 包含[1, 2, 3]
[4, 5, 6]
this.setState({pictures: pics})
在上面的例子中,this.state.pictures 将包含图片,即this.state.pictures = [4, 5, 6]
this.setState(prevState => ({
pictures: prevState.pictures.concat(pics)
}))
而在上面的代码片段中,this.state.pictures 将包含以前的图片 + 图片,即this.state.pictures = [1, 2, 3, 4, 5, 6]
无论哪种方式,您都可以对其进行调整以满足您的 API 需求,如果它像分页响应,您最好将每个请求的结果连接起来,否则,如果您每次都获得整个数组,只需分配整个数组。
常规 setState VS 函数式 setState
现在,您的问题主要是是与对象一起使用还是与函数一起使用。setState
人们出于不同的原因使用它们,现在据说该功能是安全的,因为执行了一种称为协调过程的东西,其中在频繁或同时触发时合并内部的多个对象,并在一次中应用更改,有点像批处理过程。在以下情况下,这可能会导致一些意外结果。setState
React
setState
例:
increaseScoreBy3 () {
this.setState({score : this.state.score + 1});
this.setState({score : this.state.score + 1});
this.setState({score : this.state.score + 1});
}
正如你所期望的那样,分数会增加 3,但 React 所做的是合并所有对象并只更新一次分数,即增加 1
这是函数回调大放异彩的情况之一,因为函数上不会发生协调,执行以下代码将按预期执行操作,即将分数更新为 3
increaseScoreBy3 () {
this.setState(prevState => ({ score: prevState.score + 1 }));
this.setState(prevState => ({ score: prevState.score + 1 }));
this.setState(prevState => ({ score: prevState.score + 1 }));
}
评论
this.setState({score : this.state.score + 1})
where functional callback shines because reconciliation does not happen on functions and executing the below code will do things as expected
你能解释一下吗?@Nandu
首先,在您的情况下,这两种语法是完全不同的,您可能正在寻找的是两者之间的区别
this.setState({pictures: this.state.picture.concat(pics)})
和
this.setState(prevState => ({
pictures: prevState.pictures.concat(pics)
}))
要理解为什么第二种方法是首选方法,您需要了解 React 在内部的作用。setState()
React 将首先将你传递给的对象合并到当前状态中。然后它将开始和解的事情。由于调用可能不会立即更新您的状态。setState()
setState()
React 可以将多个调用批处理到单个更新中以获得更好的性能。setState()
考虑一个简单的情况,为了理解这一点,在函数中,您可以调用不止一次,例如:setState()
myFunction = () => {
...
this.setState({pictures: this.state.picture.concat(pics1)})
this.setState({pictures: this.state.picture.concat(pics1)})
this.setState({pictures: this.state.picture.concat(pics1)})
...
}
这在简单的应用程序中不是一个有效的用例,但随着应用程序变得复杂,可能会从多个地方发生多个调用,做同样的事情。setState()
因此,现在为了执行有效的更新,React 通过提取传递给每个调用的所有对象来执行批处理工作,将它们合并在一起以形成单个对象,然后使用该单个对象来执行。根据文档:setState()
setState()
setState()
这种形式也是异步的,同一周期内的多个调用可以批处理在一起。例如,如果您尝试在同一周期内多次增加物料数量,则将导致以下等效结果:
setState()
Object.assign( previousState, {quantity: state.quantity + 1}, {quantity: state.quantity + 1}, ... )
后续调用将覆盖同一周期中先前调用的值,因此数量只会递增一次。如果下一个状态取决于当前状态,我们建议改用更新程序函数形式:
this.setState((state) => { return {quantity: state.quantity + 1}; });
有关详细信息,请参阅:
因此,如果任何对象包含相同的键,则存储具有相同键的最后一个对象的键值。因此,更新仅发生一次,最后一个值。
评论
快速回答:
始终使用 setState() 的函数形式。
this.setState((state, props)=>({
someValue: state.somevalue + 1
}));
这种方法不易出错,有助于消除一些非常难以发现的错误。即使 react 批处理多个此类更新,每个更新都是单独的函数调用,后续更新不会导致其中一些更新丢失。
另一种方法
this.setState({
someValue: state.somevalue + 1
});
如果频繁重复,可能会导致一些更新丢失,因为 React 会批处理这种频繁的更新。
评论
state.pictures
pics
state.pictures
state.pictures
pics