内容简介:原文地址:组件状态(state)是一种持有,处理和使用信息的方式。state包含的信息仅作用于一个给定组件的内部,并允许你根据它实现组件的一些逻辑。state通常是一个POJO(Plain Old Java[Script] Object)对象,改变它是使得组件重新render自己的方式之一。state是react背后原理的重要基础概念之一,但是它也有一些特点使得它用起来会有点难以捉摸并且有可能会导致在你的应用中出现一些预料之外的行为。
原文地址: medium.com/@baphemot/u…
组件状态(state)是一种持有,处理和使用信息的方式。state包含的信息仅作用于一个给定组件的内部,并允许你根据它实现组件的一些逻辑。state通常是一个POJO(Plain Old Java[Script] Object)对象,改变它是使得组件重新render自己的方式之一。
state是react背后原理的重要基础概念之一,但是它也有一些特点使得它用起来会有点难以捉摸并且有可能会导致在你的应用中出现一些预料之外的行为。
更新State唯一你能直接写this.state的地方应该是组件的构造函数中。在其它所有地方你都应该使用this.setState函数,它接受一个对象作为参数,这个对象最终会被合并到组件的当前状态中。
而在技术上你是可以通过this.state={//a new object}这种方式直接修改状态的,但是它不会引起组件使用新的值去重新渲染,然后导致状态不一致的问题。
setState是异步的事实上setState会引起的一致性处理(reconciliation)——重新渲染组件树的过程,是下一个属性的基础即setState是异步的。这允许我们在单个作用域内多次调用setState而不会触发不必要的重新渲染整个树。
这就是为什么在你更新state后并不能立马看见新的值。
// 假设 this.state = { value: 0 } this.setState({ value: 1 }); console.log(this.state.value); // 0 复制代码
React 也会尝试将多次setState调用组合或者批处理为一次调用:
// 假设 this.state = { value: 0 }; this.setState({ value: this.state.value + 1}); this.setState({ value: this.state.value + 1}); this.setState({ value: this.state.value + 1}); 复制代码
在上面所有的调用完成后,this.state.value将是1,而不是我们的期望值3。那么怎么得到期望值3呢?
setState接受一个函数作为它的参数如果你传递一个函数作为setState的第一个参数,React将会使用在当前调用时刻的state去调用它并期望你返回一个对象合并到state中。所以你可以把我们上面的代码改成下面这样即可:
// 假设 this.state = { value: 0 }; this.setState((state) => ({ value: state.value + 1})); this.setState((state) => ({ value: state.value + 1})); this.setState((state) => ({ value: state.value + 1})); 复制代码
这样this.state.value 的值就是 3了,就和上面我们认为期望值应该是3相一致了。 记住当在更新state为一个值的时候应始终使用这种语法,它的计算是基于前面的一个状态的。
setState是同步的吗???记住你刚才学习到setState是异步的。事实证明并非始终如此。这取决于执行上下文,请看下面的例子:
render() { return <button onClick={this.inc}>Click to update</button> } inc() { console.log('before: ' + this.state.test); this.setState({ test: this.state.test+1 }); console.log('after: ' + this.state.test); } 复制代码
点击按钮元素将会导致你的console中显示:
// click! before: 1 after: 1 // click! before: 2 after: 2 复制代码
但如果我们添加以下代码:
componentDidMount() { setInterval(this.inc, 1000); } 复制代码
我们将在console中看到:
before: 1 after: 2 before: 2 after: 3 复制代码
因此,我们需要学习什么时候期望得到哪种行为吗?并不是如此。假设setState的确是异步是非常安全的,因为在未来它就是如此。
setState接受一个回调函数如果你需要执行一些函数,或者验证状态是否真的有更新正确。你还可以给setState传递一个函数作为第二个参数,这个函数会在状态更新完毕后得到执行。请记住由于单个块内的所有更新会被合并成一个,这将导致每个setState中的回调中得到的state值是全更新的state。
另外一种可以保证你的代码执行是在更新完成以后的方式是将执行代码放在componentWillUpdate 或者 componentDidUpdate中。然而对比回调函数的方式,这两个方法会在shouldComponentUpdate中阻止你的组件更新时不会被调用。
常见错误其中最常见的错误之一就是在构造函数中使用props设置state的值。考虑如下代码:
class Component extends React.Component { constructor(props) { super(props); this.state = { value: this.props.value }; } render() { return <div>The value is: {this.state.value}</div> } } 复制代码
如果它的父组件这样render它:
<Component value={42} /> 复制代码
它将会正确渲染value为42,但如果父组件中修改成如下:
<Component value={13} /> 复制代码
那它仍会认为this.state.value是42,这是因为React并不会销毁组件并重新创建它——它会重用一旦渲染好的组件,并且不会重新执行构造函数。要避免这个问题,你应该不要将props赋值给state,而应在render方法中使用this.props.value。 如果你还是想要使用state(如果你的props是以一种非常复杂的计算的使用模式,你不希望每一次render都执行这些复杂的计算),你还可以实现一种在需要的时候才去更新state的解决方案,例如:
class Component extends React.Component { constructor(props) { super(props); this.state = { value: this.props.value }; } componentWillReceiveProps(nextProps) { if(nextProps.value !== this.props.value) { this.setState({value: nextProps.value}); } } render() { return <div>The value is: {this.state.value}</div> } } 复制代码
请记住任何componentWill*函数都不是一个合适的地方去触发side effect(如ajax请求),所以请使用 componentDidUpdate(previousProps, previousState),同样也提供和上面类似的if防护语句确保在没有变化时不会执行相关代码。
写在最后的话:这篇文章在Medium中获得超过2.1K的赞,挺不错的,值得翻译! 翻译如有不正,欢迎留言指出!
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 理解原型其实是理解原型链
- 要理解深度学习,必须突破常规视角去理解优化
- 深入理解java虚拟机(1) -- 理解HotSpot内存区域
- 荐 【C++100问】深入理解理解顶层const和底层const
- 深入理解 HTTPS
- 深入理解 HTTPS
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
企业应用架构模式
Martin Fowler / 王怀民、周斌 / 机械工业出版社 / 2010-4 / 59.00元
《企业应用架构模式》作者是当今面向对象软件开发的权威,他在一组专家级合作者的帮助下,将40多种经常出现的解决方案转化成模式,最终写成这本能够应用于任何一种企业应用平台的、关于解决方案的、不可或缺的手册。《企业应用架构模式》获得了2003年度美国软件开发杂志图书类的生产效率奖和读者选择奖。《企业应用架构模式》分为两大部分。第一部分是关于如何开发企业应用的简单介绍。第二部分是《企业应用架构模式》的主体......一起来看看 《企业应用架构模式》 这本书的介绍吧!