React生命周期详解
来源:互联网 发布:交换机端口抓包 编辑:程序博客网 时间:2024/05/22 04:23
React 摒弃了十分消耗性能的手动DOM操作,通过控制组件state和props的改变 利用 diff算法 改变DOM,当DOM需要变动,都会先在虚拟DOM上发生,将实际发生变动的部分渲染在真实的DOM上,这样能极大的提高性能
React 中的组件本质上可以理解为是一个状态机,将状态和输出一一对应,这样可以比较直观的反应程序在不同状态时,对应什么样的输出.
组件的 生命周期 由3个部分组成:初始化阶段,运行中阶段,销毁阶段,每个阶段React都提供了不同的钩子函数供开发者使用
初始化阶段
- getDefaultProps 初始化组件属性的默认值,只调用一次 , 该方法返回一个对象并缓存起来。然后与父组件指定的 props 对象合并,最后赋值给 this.props 作为该组件的默认属性
- getInitialState 初始化每个实例的状态 , 初始化组件的 state 的值。其返回值会赋值给组件的 this.state 属性
- componentWillMount 组件render之前,可以修改状态.如果此时在 componentWillMount 中调用 setState,是不会触发 reRender,而是进行 state 合并
- render 根据 state 的值,生成页面需要的虚拟 DOM 结构,并返回该结构
- componentDidMount 在render完成后 组件渲染到页面时触发 , 对根据虚拟 DOM 结构而生的真实 DOM 进行相应的处理。组件内部可以通过 ReactDOM.findDOMNode(this) 来获取当前组件的节点,然后就可以像 Web 开发中那样操作里面的 DOM 元素了
state属性介绍:
它是用来存储组件自身需要的数据。它是可以改变的,它的每次改变都会引发组件的更新。这也是 ReactJS 中的关键点之一。
即每次数据的更新都是通过修改 state 属性的值,然后 ReactJS 内部会监听 state 属性的变化,一旦发生变化,就会触发组件的 render 方法来更新 DOM 结构。
运行中阶段
- componentWillReceiveProps 当组件接收到新的 props 时,会触发该函数。在改函数中,通常可以调用 this.setState 方法来完成对 state 的修改。如果此时在 componentWillReceiveProps 中调用 setState,是不会触发 reRender,而是进行 state 合并
- shouldComponentUpdate 该方法用来拦截新的 props 或 state,然后根据事先设定好的判断逻辑,做出最后要不要更新组件的决定。
- componentWillUpdate 当上面的方法拦截返回 true 的时候,就可以在该方法中做一些更新之前的操作,进行渲染之前触发 但它不能修改props和state
- render 根据一系列的 diff 算法,生成需要更新的虚拟 DOM 数据。(注意:在 render 中最好只做数据和模板的组合,不应进行 state 等逻辑的修改,这样组件结构更加清晰)
- componentDidUpdate 该方法在组件的更新已经同步到 DOM 中去后触发,我们常在该方法中做一 DOM 操作
注意:此时 this.state 虽然获取到更新数据,但只能在内部源码中使用,我们在开发时,若在 componentWillReceiveProps 中调用 setState,那么在 componentWillReceiveProps、shouldComponentUpdate 和 componentWillUpdate 中还是无法获取到更新后的 this.state,即此时访问的this.state 仍然是未更新的数据,只有在 render 和 componentDidUpdate 中才能获取到更新后的this.state。
注意:禁止在 shouldComponentUpdate 和 componentWillUpdate 中调用 setState,会造成循环调用,直至耗光浏览器内存后崩溃。
销毁阶段
- componentWillUnmount 在销毁操作真正执行之前调用,我们通常会做一些取消事件绑定、移除虚拟 DOM 中对应的组件数据结构、销毁一些无效的定时器等工作。这些事情都可以在这个方法中处理。
示例代码
class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } componentDidMount() { this.timerID = setInterval( () => this.tick(), 1000 ); } componentWillUnmount() { clearInterval(this.timerID); } tick() { this.setState({ date: new Date() }); } render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); }}ReactDOM.render( <Clock />, document.getElementById('root'));
可以用下面这张图,来详细说明 React 组件生命周期中钩子函数 的触发顺序
初始化简单的实例
var MyFirstComponent = React.createClass({ // 只调用一次,实例之间共享引用 getDefaultProps: function () { // 下面的console.log()是在实例化组件时就被调用 console.log('getDefaultProps, 1'); return {name: 'Tom'}; }, // 初始化每个实例特有的状态 getInitialState: function () { console.log('getInitialState, 2'); return {ready: false}; }, // render之前最后一次修改状态的机会 componentWillMount: function () { console.log('componentWillMount, 3'); this.setState({ready: true}); }, // 只能访问this.props和this.state,只有一个顶层组件,不可以修改状态和DOM输出 render: function () { console.log('render, 4'); return ( <p ref="textNode"> Hello, {this.props.name ? this.props.name : 'World'} <br/> {'' + this.state.ready} </p> ) }, // 成功render并渲染完成真实DOM之后触发,可以修改DOM componentDidMount: function () { console.log('componentDidMount, 5'); }});ReactDOM.render( <MyFirstComponent />, document.getElementById('example'));
控制台显示的结果如下,可以很直观的看到各个函数的执行顺序
运行简单例子
var ChildComponent = React.createClass({ // 组件将要接受到属性时触发 componentWillReceiveProps: function () { console.log('componentWillReceiveProps 1'); }, // 组件是否需要更新,返回false则阻止render调用 // 这个函数我们一般谨慎使用,只有在性能调优时会使用 shouldComponentUpdate: function () { console.log('shouldComponentUpdate 2'); return true; }, // 组件接收到新的props或者state后,进行渲染之前触发 // 但它不能修改props和state componentWillUpdate: function () { console.log('componentWillUpdate 3'); }, render: function () { console.log('render, 4'); return ( <p ref="myText"> Hello, {this.props.name ? this.props.name : 'World'} </p> ) }, // 在render完成后 组件完成更新渲染到页面时触发 componentDidUpdate: function () { console.log('componentDidUpdate 5'); // 为了演示方便,这里使用了jQuery,需要在HTML中先加载jQuery库 $(this.refs.myText).append("\nI'm here!"); }});var ParentComponent = React.createClass({ // 初始化状态 getInitialState: function () { return {name: ''} }, handleChange: function (event) { this.setState({name: event.target.value}); }, render: function () { return ( <div> <ChildComponent name={this.state.name} /> <input className="form-control" type="text" onChange={this.handleChange} /> </div> ); }});ReactDOM.render( <ParentComponent />, document.getElementById('example'));
参考资料(https://facebook.github.io/react/docs/react-component.html)
- React组件生命周期详解
- React组件生命周期详解
- React生命周期详解
- React-Native生命周期详解
- React组件生命周期详解
- React生命周期详解
- React—组件生命周期详解
- React生命周期及事件详解
- React—组件生命周期详解
- React生命周期及事件详解
- (十二)React-Native-生命周期详解
- React组件的生命周期(LeftCycle)详解
- React Native (2)生命周期 详解
- 关于对 React 生命周期方法的详解
- React源码分析4 — React生命周期详解
- React生命周期
- React 生命周期
- React生命周期
- C++输出空心三角形
- 2017_02_25周末信竞总结(上)——NOIP2008
- linux安装mysql之后,需要修改初始密码
- Mac 10进制转换16进制
- 微信开发坑哭了自己Code、OpenID、WXConfig、TOKEN、TICKET处处是坑
- React生命周期详解
- Qcharts之饼图
- 欢迎使用CSDN-markdown编辑器
- POJ 3262 Protecting the Flowers 贪心
- hdu1233还是畅通工程
- Linux第一课的总结
- jedis(redis)整合spring,包括jedis客户端单机版,jedis集群版配置 ,连接池配置
- hql 语法与详细解释
- 借鉴面试总结