1. 本质
一句话概括, props 是组件对外的接口, state 是组件对内的接口. 组件内可以引用其他组件, 组件之间的引用形成了一个树状结构(组件树), 如果下层组件需要使用上层组件的数据或方法, 上层组件就可以通过下层组件的 props 属性进行传递, 因此 props 是组件对外的接口. 组件除了使用上层组件传递的数据外, 自身也可能需要维护管理数据, 这就是组件对内的接口 state. 根据对外接口 props 和对内接口 state, 组件计算出对应界面的 UI=>UI = Component(props, state).
组件的 props 和 state 都和组件最终渲染出的 UI 直接相关. 两者的主要区别是: state 是可变的, 是组件内部维护的一组用于反映组件 UI 变化的状态集合; 而 props 是组件的只读属性, 组件内部不能直接修改 props, 要想修改 props, 只能在该组件的上层组件中修改. 在组件状态上移的场景中, 父组件正是通过子组件的 props, 传递给子组件其所需要的状态.
请务必牢记, 并不是组件中用到的所有变量都是组件的状态! 当存在多个组件共同依赖同一个状态时, 一般的做法是状态上移, 将这个状态放到这几个组件的公共父组件中.
2. 修改 State
1)不能直接修改 State.
直接修改 state, 组件并不会重新重发 render. 例如:
- // 错误
- this.state.title = 'React';
正确的修改方式是使用 setState():
- // 正确
- this.setState({title: 'React'});
2)State 的更新是异步的.
调用 setState, 组件的 state 并不会立即改变, setState 只是把要修改的状态放入一个队列中, React 会优化真正的执行时机, 并且 React 会出于性能原因, 可能会将多次 setState 的状态修改合并成一次状态修改. 所以不能依赖当前的 state, 计算下个 state. 当真正执行状态修改时, 依赖的 this.state 并不能保证是最新的 state, 因为 React 会把多次 state 的修改合并成一次, 这时, this.state 还是等于这几次修改发生前的 state. 另外需要注意的是, 同样不能依赖当前的 props 计算下个 state, 因为 props 的更新也是异步的.
举个例子, 对于一个电商类应用, 在我们的购物车中, 当点击一次购买按钮, 购买的数量就会加 1, 如果我们连续点击了两次按钮, 就会连续调用两次
this.setState({quantity: this.state.quantity + 1})
, 在 React 合并多次修改为一次的情况下, 相当于等价执行了如下代码:
- // 错误
- Object.assign(
- previousState,
- {quantity: this.state.quantity + 1},
- {quantity: this.state.quantity + 1}
- )
后面的操作覆盖掉了前面的操作, 最终购买的数量只增加了 1 个.
如果你真的有这样的需求, 可以使用另一个接收一个函数作为参数的 setState, 这个函数有两个参数, 第一个参数是组件的前一个 state(本次组件状态修改成功前的 state), 第二个参数是组件当前最新的 props. 如下所示:
- // 正确
- this.setState((preState, props) => ({
- counter: preState.quantity + 1;
- }))
3)State 的更新是一个浅合并 (Shallow Merge) 的过程.
当调用 setState 修改组件状态时, 只需要传入发生改变的状态变量, 而不是组件完整的 state, 因为组件 state 的更新是一个浅合并 (Shallow Merge) 的过程. 例如, 一个组件的 state 为:
- this.state = {
- title : 'React',
- content : 'React is an wonderful JS library!'
- }
当只需要修改状态 title 时, 只需要将修改后的 title 传给 setState:
this.setState({title: 'Reactjs'});
React 会合并新的 title 到原来的组件 state 中, 同时保留原有的状态 content, 合并后的 state 为:
- {
- title : 'Reactjs',
- content : 'React is an wonderful JS library!'
- }
来源: http://www.bubuko.com/infodetail-2614852.html