1.1. 状态理解
React的数据流:由父节点传递到子节点(由外到内传递),如果顶层组件某个prop改变了,React会向下传递,重新渲染所有使用过该属性的组件。除此之外React 组件内部还具有自己的状态,这些状态只能在组件内部修改。通过与用户的交互(点击),实现不同状态(显示、隐藏、数量增加...),然后渲染UI,让用户界面和数据保持一致。React中只需更新组件的state,然后根据新的 state 重新渲染用户界面。
this.props 属性:由父节点传入到组件内部,只读,不可修改。
this.state 状态:由组件自己创建,可以修改,一般由用户交互产生新的状态(数据)。
1.2. 状态案例
开发一个开关组件,组件有两种状态,开、关。修改状态方式,通过this.setState({}),请勿使用this.state.
<!DOCTYPE html> <html> <head> <script src="../build/react-0.14.0.js"></script> <script src="../build/react-dom.js"></script> <script src="../build/browser.min.js"></script> </head> <body> <div id="example"> </div> <script type="text/babel"> class MySwitch extends React.Component{ constructor(props){ super(props); this.state = { isEdit:false //false :关闭 true:打开 }; this.handleClick = this.handleClick.bind(this); } render(){ return (<button onClick={this.handleClick}>{this.state.isEdit?‘关闭‘:‘打开‘}</button>) } handleClick(e){ this.setState({ isEdit:!this.state.isEdit }); } } ReactDOM.render(<MySwitch/>,document.getElementById(‘example‘)) </script> </body> </html>
1.3. state与props区别
state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。这就是为什么有些容器组件需要定义 state 来更新和修改数据。而组件只能通过 props 来传递数据。
1.4state注意事项
上面已经说明了setState的基本使用。但是 setState
不会立即改变 this.state
,而是挂起状态转换,调用 setState
方法后立即访问 this.state
可能得到的是旧的值。如下面的例子:
setState
方法不会阻塞state更新完毕
第二个 setState
可能还没等待第一次的state更新完毕就开始执行了,所以最后count可能只加了1。
this.setState({ count: this.state.count + 1 }); this.setState({ count: this.state.count + 1 });
setState方法还有第二个参数,相当于回调函数:
this.setState({ count: this.state.count + 1 }, () => { this.setState({ count: this.state.count + 1 }); });
不过看起来很怪, es6
中可以使用 Promise
更优雅的使用这个函数,封装一下 setState
function setStateAsync(nextState){ return new Promise(resolve => { this.setState(nextState, resolve); }); }
上面的例子就可以这样写
async func() { ... await this.setStateAsync({count: this.state.count + 1}); await this.setStateAsync({count: this.state.count + 1}); }
顺眼多了。
函数方式
nextState
也可以是一个 function
,称为状态计算函数,结构为 function(state, props) => newState
。这个函数会将每次更新 加入队列 中,执行时通过当前的 state
和 props
来获取新的 state
。那么上面的例子就可以这样写
this.setState((state, props) => { return {count: state.count + 1}; }); this.setState((state, props) => { return {count: state.count + 1}; });
每次更新时都会提取出当前的state,进行运算得到新的state,就保证了数据的同步更新。
控制渲染
默认调用 setState
都会重新渲染视图,但是通过 shouldComponentUpdate()
函数返回 false
来避免重新渲染。
如果可变对象无法在 shouldComponentUpdate()
函数中实现条件渲染,则需要控制 newState
与 prevState
不同时才调用 setState
来避免不必要的重新渲染。