WdBly Blog

懂事、有趣、保持理智

WdBly Blog

懂事、有趣、保持理智

周维 | Jim

603927378@qq.com

react 生命周期(一)

react v16版本前生命周期详解

image.png

初始化数据阶段

使用React.creatClass创建组件会执行到getDefaultProps 和 getInitialState钩子函数,使用ES6的类继承则没有这两个钩子函数。

React v15.5.0中已经废弃了creatClass方法,推荐使用ES的方式创建组件

// 使用ES6创建组件设置默认props class Test extends React.Component { ... } Test.defaultProps = {name: "zhou"} // 使用ES7创建组件设置默认props class Test extends React.Component { static defaultProps = { name: "demo" } } // 使用ES6+创建组件设置默认state 在constructor中设置 class Test extends React.Component { constructor(props){ super(props) this.state = { name: "zhou" } } }

ES6中只有静态方法,没有静态属性,static 属性是ES7的提案,需要babel7+编译。

componentWillMount 钩子

在接收到props,state之后,在渲染之前执行

该方法在首次渲染之前调用,也是再 render 方法调用之前修改 state 的最后一次机会。

首次渲染state中的值会自动渲染到render中,不用调用setState方法,在constructor中初始化state后可以在componentWillMount中修改state。

componentWillMount() { // 实际上最好不要在此修改默认的state this.state.curr_value = 2; } // 也可在render中修改state render() { this.state.curr_value = 3; }

注意, 在此生命周期中不要去使用ajax获取并设置组件数据, 因为你不能保证在ajax resolve后你的组件已经挂载完毕

render 钩子

render方法中会创建虚拟DOM节点,通过this.props和this.state访问数据,最终返回一个React Compenont或者null。

当render生成虚拟节点树(virtual DOM)后,会采用对比算法来决定如何更新真实的视图。

componentDidMount

此钩子不会在服务端渲染中执行

此方法被调用时代表真实的DOM结构已经被渲染出来了。可以在此方法内获取真实的DOM。

此方法也只会调用一次, 后续如果state或者props改变引起了重新render都不会再次执行此方法

获取真实DOM:
// 1. 获取html特征 componentDidMount() { var root = document.querySelectorAll("#root p"); // 不能用于直接获取一个自定义组件 var text = document.querySelectorAll("#text"); } render() { return ( <div id="root"> <p>{this.props.curr_value}</p> <p>{this.state.curr_value}</p> <Text id="text"/> </div> ); } // 2. 通过ref componentDidMount() { var pTag = this.refs.pTag ; console.log(pTag.innerHTML); // pTag var textComponent= this.refs.textComponent; console.log(textComponent); // React Component } render() { return ( <div> <p ref="pTag">pTag</p> <Text ref="textComponent"/> </div> ); }

image.png

ref的值需要保持唯一,否则后面的ref会覆盖之前的。

如果想要获取到组件的dom结构可使用ReactDOM.findDomNode

在此生命周期中我们可以使用ajax获取数据, 也可使用setState渲染数据

运行阶段

此时组件已经渲染好并且用户可以与它进行交互,比如鼠标点击,手指点按,当组件运行中时若是自上而下的props发生了改变或者自身设置了新的state(交互事件,定时器,http请求等触发),会依次执行下面的钩子函数。

componentWillReceiveProps

组件在运行中接收到props后触发,有可能接收的props没有发生改变。

自身的setState不会触发此生命周期

在componentWillReceiveProps中可以写一些逻辑来设置新的state,适用于组件都是使用state渲染数据的情况,因为若是组件本身就是通过props渲染,则只需在下一步中判断是否重新渲染即可,如下:

componentWillReceiveProps(props){ if(props.value !== undefined){ this.setState({ value: props.value }) } }

小组件可设置成纯state控制组件,将props都转换成state, redux,MobX这种类似于纯props控制组件,将state做为props从外部传入,适合一些公共状态的设置。

这种通过props来设置state的不大适用于大型组件

shouldComponentUpdate

某些场景下,我们不希望正在运行中的组件重新渲染,如props或state的值并没有改变,或者props是一个意料之外的值等情况,这时我们可以在此钩子函数中返回false用以阻止下面的钩子函数的执行。

shouldComponentUpdate(nextProps, nextState) { // this.state.value = "test" 有效 // nextState.value = "test" 有效 // this.setState({value: "test"}) //死循环 return this.state.value === nextState.value; }

不能再shouldComponentUpdate中调用setState方法. 但是可以直接设置state: this.state.value = “set”;且是有效的设置

此生命周期是我们性能优化的地方, 他允许我们:只有当所关心的props的改变的时候才更新, 无关的props更新时不去更新

image.png

componentWillUpdate

和componentWillMount类似,在接收到props和state后,在重新渲染前执行此钩子函数。

不能在此钩子中调用setState()方法

componentWillUpdate(nextProps, nextState) { // this.state.value = "test" 有效 // nextState.value = "test" 有效 // this.setState({value: "test"}) //死循环 最终栈溢出 }

基本用不到的生命周期

componentDidUpdate

和componetDidMount类似, 当render生成的虚拟DOM最终生成了真实DOM后会触发此钩子.

销毁阶段

react 组件的销毁会有如下场景:

路由切换

react路由同样是组件的思想, 不同的路由渲染不同的组件, 当路由切换时, 对应的组件将被卸载, 而新的组件将被加载, 且没有类似Vue中的keep-alive的组件

条件切换

render() { return ( <div id="root"> <p ref="pTag" onClick={() => this.setState({ curr_value: 2 })}>{this.state.curr_value}</p> {this.state.curr_value === 1 && <Text value={this.state.curr_value} /> } </div> ); }

当state的改变触发重新渲染后, Text组件不在有出现的条件, 此时组件被销毁

手动卸载

移除一个已经加载到DOM中的React组件,并清除对应的事件处理器和状态

ReactDOM.render( <TestFormSubmit curr_value={111}/>, document.getElementById('root') ); var root= document.getElementById("root"); var result = ReactDOM.unmountComponentAtNode(root); console.log(result); // true

在组件即将销毁时我们需要在此钩子中处理一些问题

清除事件绑定或定时器

componentWillUnmount(){ clearInterval(this.timer); xx.removeEventListener("click", fn); }

清理异步操作

// 异步请求完成后不再设置state, 否则你将得到一个警告 componentWillUnmount(){ this.setState = (state, callback) => { return } }