在组件的整个生命周期中,随着该组件的props或者state的变化,它的DOM表现也将有相应的改变,一个组件就是一个状态机,对于特定的输入,它总会返回一致的输出。
React为每个组件提供了勾子函数去响应不同的时期–创建时,存在时以及销毁时。
当你首次使用一个组件类时,你会看到下面的这些方法依次被调用:
对于组件类来说,这个方法只会被调用一次,该组件类的所有后续应用,getDefaultPops将不会再被调用,它用于返回组件实例的默认props值,值得注意的是,任何引用类型的值(如数组,对象),都会在所有实中共享,而不是每个组件实例拥有单独的副本,所以不要在组件实例中去修改props,把它当成只读的数据最好。
对于每个组件实例来讲,这个方法只会调用一次,注意它和getDefaultPops的调用是有区别的,getDefaultPops是对于组件类来说只调用一次,后续该类的应用都不会被调用,而getInitialState是对于每个组件实例来讲都会调用,并且只调一次。它用来初始化每个实例的state,在这个方法里,可以访问组件的props.值得注意的是,在getInitialState方法中,尝试通过this.props来创建state的做法是一种反模式。React专注于维护数据的单一来源。
//反模式 var CountDown = React.createClass({ getDefaultPops:function(){ return { date:new Date() } }, getInitialState:function(){ retrun { surplus:this.props.date - new Date() } }, render:function(){ return ( <div>{this.state.surplus}</div> ) } })
上面这种就是一种反模式,经过计算后的值不应该赋给state,正确的模式应该是在渲染时计算这些值。这样保证了计算后的值永远不会与派生出它的props值不同步。
//正确写法 var CountDown = React.createClass({ getDefaultPops:function(){ return { date:new Date() } }, render:function(){ var surplus = this.props.date - new Date(); return ( <div>{surplus}</div> ) } })
然而,如果你的目的并不是同步,而是简单的初始化state,那么在getInitialState方法中使用props是没有问题的。比如:
//简单的初始化state var Checkbox = React.createClass({ getDefaultPops:function(){ return { checked:false } }, getInitialState:function(){ return { checked:this.props.checked } }, render:function(){ return ( <div className="checkbox"> <input type="checkbox" checked={this.state.checked} /> </div> ) } })
此方法在初始化之后,渲染之前被调用。
render方法会创建一个虚拟DOM,用来表示组件的输出。对于一个组件来讲,render方法是唯一一个必需的方法。render方法需要满足下面几点:
– 只能通过this.props和this.state访问数据
– 可以返回null,false或者任何React组件
– 只能出现一个顶级组件,不能返回一组元素(新手特别注意)
render方法返回的结果并不是真正的DOM元素,而是一个虚拟的表现,类似于一个DOM tree的结构的对象。react之所以效率高,就是这个原因。
在render方法成功执行并真实的DOM已经被渲染后,componentDidMount方法才会被执行,你可以在该方法内部获取DOM节点,并操作它。
此时组件已经渲染好并且用户可以与它进行交互,比如鼠标点击,手指点按,或者其它的一些事件,导致应用状态的改变,你将会看到下面的方法依次被调用
1. componentWillReceiveProps
2. shouldComponentUpdate
3. componentWillUpdate
4. render
5. componentDidUpdate
组件的props属性可以通过父组件来更改,这时,componentWillReceiveProps将来被调用。可以在这个方法里更新state,以触发render方法重新渲染组件。
//实现一个简单的全选与全不选效果 var Checkbox = React.createClass({ getDefaultPops:function(){ return { checked:false } }, getInitialState:function(){ return { checked:this.props.checked } }, componentWillReceiveProps:function(nextProps){ if(nextProps.checked !== this.state.checked){ this.setState({ checked:nextProps.checked }); } }, render:function(){ <div className="checkbox"> <input type="checkbox" checked={this.state.checked} /> </div> } }); var AllChoose = React.createClass({ getDefaultPops:function(){ return { checked:false } }, getInitialState:function(){ return { checked:this.props.checked } }, handleChange:function(){ this.setState({ checked:!this.state.checked }); }, render:function(){ return ( <div className="checkbox"> <input type="checkbox" checked={this.state.checked} onChange={this.handleChange}/> <Checkbox checked={this.state.checked}/> <Checkbox checked={this.state.checked}/> <Checkbox checked={this.state.checked}/> </div> ); } });
如果你确定组件的props或者state的改变不需要重新渲染,可以通过在这个方法里通过返回false来阻止组件的重新渲染,返回false则不会执行render以及后面的componentWillUpdate,componentDidUpdate方法。继续上面的例子,比如上面的第二个checkbox因为某些原因为禁用了,那么即使全选这个checkbox被选中了,它也不应该跟着一起被选中,所以Checkbox这个组件还需要作一些小调整
var Checkbox = React.createClass({ getDefaultPops:function(){ return { checked:false, disabled:false } }, getInitialState:function(){ return { checked:this.props.checked, disabled:this.props.disabled } }, componentWillReceiveProps:function(nextProps){ if(nextProps.checked !== this.state.checked){ this.setState({ checked:nextProps.checked }); } }, shouldComponentUpdate:function(){ return !this.state.disabled //当checkbox的disabled属性为true时,取反,返回false,阻止重新渲染 }, render:function(){ <div className="checkbox"> <input type="checkbox" checked={this.state.checked} /> </div> } });
这个方法和componentWillMount类似,在组件接收到了新的props或者state即将进行重新渲染前,该方法会被调用,注意不要在此方面里再去更新props或者state.
这个方法和componentDidMount类似,在组件重新被渲染之后,它会被调用。可以在这里访问并修改DOM。
随着一个组件从它的层级结构中被移除,这个组件的生命也算是走到了尽头,此时componentWillUnmout会被执行,提供一个让你做一些清理工作的机会。
比如现在有一个组件,里面有一个循环执行的函数,当这个组件被销毁时,我们需要停止这个循环,否则会造成资源上的浪费,这个停止的语句就可以写在componentWillUnmout里。
//一个简单的计时器 var Clock = React.createClass({ getInitialState:function(){ return { now:new Date()-0 } }, tick:function(){ this.setState({now:new Date()-0}) }, componentDidMount:function(){ this.interval = setInterval(this.tick,1000); }, componentWillUnmout:function(){ clearInterval(this.interval); //清除setInterval,释放资源 }, render:function(){ return ( <div> {this.state.now} </div> ) } })
以上就是react组件在不同时间所提供的API,在每一个时间节点上都有相应的API让我们可以去处理,实现我们想要的效果。