React.js学习笔记之组件生命周期

React.js学习笔记之组件生命周期

@(React学习)

什么是组件

React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件。

组件类只能包含一个顶层标签,否则会报错。

var HelloXiaowang = React.createClass({
  render: function() {
    return <h1>Hello {this.props.name}</h1>;
  }
});

ReactDOM.render(
  <HelloXiaowang name="junyan" />,document.getElementById('shuaige')
);

上面代码中,变量 HelloXiaowang 就是一个组件类。模板插入 HelloXiaowang /> 时,会自动生成 HelloXiaowang 的一个实例(下文的"组件"都指组件类的实例)。

render

所有组件类都必须有自己的render方法,用于输出组件
ReactElement render ( )

当调用的时候,会检测 this.props 和 this.state,返回一个单子级组件。该子级组件可以是虚拟的本地 DOM 组件(比如 div /> 或者 React.DOM.div()),也可以是自定义的复合组件。

var HelloXiaowang = React.createClass({
  render: function() {
    return <h1>Hello {this.props.name}</h1>;
  }
});

render ( ) 函数应该是纯粹的,也就是说该函数不修改组件 s

tate,每次调用都返回相同的结果,不读写 DOM 信息,也不和浏览器交互(例如通过使用 setTimeout)。如果需要和浏览器交互,在 componentDidMount() 中或者其它生命周期方法中做这件事。保持 render() 纯粹,可以使服务器端渲染更加切实可行,也使组件更容易被理解。

生命周期

组件本质上是状态机,输入确定,输出一定确定

状态机本质上是状态与转移的结合。当状态发生转换时会触发不同的钩子函数,从而让开发者有机会做出相应。
组件的声明周期分成三个状态:

  • Mounting:初始化阶段(已插入真实 DOM)

  • Updating:运行中阶段(正在被重新渲染)

  • Unmounting:销毁阶段(已移出真实 DOM)

初始化阶段Mounting

类创建完成之后,就可以进行实例化。

初始化阶段可以使用的函数:

  • getDefaultProps: 只调用一次,实例之间共享引用

  • getInitialState: 初始化每个实例特有的状态

  • componentWillMount: render之前最后一次修改状态的机会。如果在这个方法内调用setState,render()将会感知到更新后的state,将会执行仅一次,尽管state改变了。

  • render: 只能访问this.props和this.state,只有一个顶层组件,不允许修改状态和DOM输出

  • componentDidMount: 成功render并渲染完成真实DOM之后触发,可以修改DOM

调用顺序

当组件在客户端被实例化,第一次被创建时,以下方法依次被调用:

  1. getDefaultProps

  2. getInitialState

  3. componentWillMount

  4. render

  5. componentDidMount

当组件在服务端被实例化,首次被创建时,以下方法依次被调用:

  1. getDefaultProps

  2. getInitialState

  3. componentWillMount

  4. render

componentDidMount 不会在服务端被渲染的过程中调用。

实例

getDefaultProps方法不是在组件创建的时候调用,而是在createClass时调用。

var count = 0;
var HelloWorld = React.createClass({
    getDefaultProps:function(){
        return {name:"dada"};
    },
    getInitialState:function(){
        return {
            myCount:count++,ready:false
        };
    },
    componentWillMount:function(){
        this.setState({ready:true});
    },
    render:function(){
        return <p>Hello,{this.props.name?this.props.name:"World"}
        <br/>{''+this.props.ready}{this.state.myCount}</p>;
    },componentDidMount:function(){
        $(ReactDOM.findDOMNode(this)).append("bianke");
    }
});
ReactDOM.render(<HelloWorld/>,document.getElementById('shuage'))

阮老师例子:

var Hello = React.createClass({
  getInitialState: function () {
    return {
      opacity: 1.0
    };
  },componentDidMount: function () {
    this.timer = setInterval(function () {
      var opacity = this.state.opacity;
      opacity -= .05;
      if (opacity < 0.1) {
        opacity = 1.0;
      }
      this.setState({
        opacity: opacity
      });
    }.bind(this),100);
  },render: function () {
    return (
      <div style={{opacity: this.state.opacity}}>
        Hello {this.props.name}
      </div>
    );
  }
});

ReactDOM.render(
  <Hello name="world"/>,document.body
);

上面代码在hello组件加载以后,通过 componentDidMount 方法设置一个定时器,每隔100毫秒,就重新设置组件的透明度,从而引发重新渲染。

另外组件的style属性的设置方式要写成style={{opacity: this.state.opacity}}

React.findDOMNode()

如果这个组件已经被初始化到DOM中,这个方法返回相应的原生浏览器的DOM元素。这个方法用于读取这个DOM的值,例如表单的值与DOM的方法。在多数情况下附加一个ref属性与DOM节点上,用来避免使用findDOMNode。当render返回null或false时,findDOMNode也返回null。

注意:

  • findDOMNode是一个用来访问底层DOM节点的出口。在大多数情况下,是不鼓励用出口,因为他穿过了组件的层

  • findDOMNode仅仅是在初始化阶段的组件起作用(因为组件已经存在于DOM结构中)。如果你尝试在尚未在初始化阶段的组件中调用这个方法(就像render()函数中组件尚未创建就调用这个方法)会抛出异常。

  • findDOMNode不能用于没有状态的组件中。

  • getDOMNode已过时,不建议使用。

运行中阶段Updating

此时组件已经渲染好并且用户可以与它进行交互,比如鼠标点击,手指点按,或者其它的一些事件,导致应用状态的改变

运行中阶段可以使用的函数

  • componentWillReceiveProps:父组件修改属性触发,可以修改新属性、修改状态。它是在组件发生改变之前触发

  • shouldComponentUpdate:返回false会阻止render调用

  • componentWillUpdate:不能修改属性与状态

  • render: 只能访问this.props和this.state,只有一个顶层组件,不允许修改状态和DOM输出

  • componentDidUpdate:可以修改DOM

componentWillReceiveProps

在组件接收到新的 props 的时候调用。在初始化渲染的时候,该方法不会调用。
用此函数可以作为 react 在 prop 传入之后,render()渲染之前更新 state 的机会。老的 props 可以通过this.props获取到。在该函数调用用this.setState()将不会引起第二次渲染。

componentWillReceiveProps: function(nextProps) {
  this.setState({
    likesIncreasing: nextProps.likeCount > this.props.likeCount
  });
}

对于 state,没有相似的方法:componentWillReceiveState。将要传进来的 prop 可能会引起 state 改变,反之则不然。如果需要在 state 改变的时候执行一些操作,请使 componentWillUpdate

shouldComponentUpdate

在接收到新的 props 或者 state,将要渲染之前调用。该方法在初始化渲染的时候不会调用,在使用 forceUpdate 方法的时候也不会。
如果确定新的 props 和 state 不会导致组件更新,则此处应该 返回 false。

shouldComponentUpdate: function(nextProps,nextState) {
  return nextProps.id !== this.props.id;
}

如果shouldComponentUpdate返回 false,则render()将不会执行,直到下一次 state 改变。

如果性能是个瓶颈,尤其是有几十个甚至上百个组件的时候,使用shouldComponentUpdate可以提升应用的性能。

默认情况下shouldComponentUpdate总会返回 true,在 state 改变的时候避免细微的 bug,但是如果总是小心地把 state 当做不可变的,在render()中只从 props 和 state 读取值,此时你可以覆盖shouldComponentUpdate方法,实现新老 props 和 state 的比对逻辑。

componentWillUpdate

在接收到新的 props 或者 state 之前立刻调用。在初始化渲染的时候该方法不会被调用。使用该方法做一些更新之前的准备工作。

你不能在此方法中使用this.setState()。如果需要更新 state 来响应某个 prop 的改变,请使用componentWillReceiveProps

componentDidUpdate

在组件的更新已经同步到 DOM 中之后立刻被调用。该方法不会在初始化渲染的时候调用。使用该方法可以在组件更新之后操作 DOM 元素。

调用顺序

每次修改 state,都会重新渲染组件,实例化后通过 state 更新组件,会依次调用下列方法:

  1. shouldComponentUpdate

  2. componentWillUpdate

  3. render

  4. componentDidUpdate

但是不要直接修改 this.state,要通过 this.setState 方法来修改。

实例

正确用法

var HelloXianrou = React.createClass({
    componentWillReceiveProps:function(newProps){
        console.log(newProps);
    },render:function () {
        console.log(4);
        return <p>Hello {this.props.name||"World"}</p>
    },componentDidUpdate:function () {
        $(ReactD.findDOMNode(this)).append("<p>大大是大帅哥</p>")
    }
});
var HelloDada = React.createClass({
    getInitialState:function () {
        return {name:''};
    },handleChange:function (e) {
        this.setState({name:e.target.value});
    },render:function () {
        return <div>
        <HelloXianrou name={this.state.name}></HelloXianrou>
        <br/>
        <input type="text" onChange={this.handleChange} />
        </div>
    }
});
ReactDOM.render(<HelloDada></HelloDada>,document.getElementById('reactDemo'))

销毁阶段Unmounting

销毁阶段可以使用的函数

componentWillUnmount:在删除组件之前进行清理操作,比如计时器和事件监听器。或者清除在 componentDidMount 中创建的 DOM 元素。

ReactDOM.unmountComponentAtNode

移除一个已经初始化DOM过的React组件,清理它的操作和状态。如果这个组件中没有初始化过的组件,这个方法没有任何作用。如果这个组件被销毁则返回true,反之返回false

实例

var HelloXianrou = React.createClass({
    render:function () {
        console.log(4);
        return <p>Hello {this.props.name||"World"}</p>
    },componentWillUnmount:function () {
        console.log("Booooooooooom!!")
    }
});
var HelloDada = React.createClass({
    getInitialState:function () {
        return {name:''};
    },handleChange:function (e) {
    /* if (e.target.value == "123") {
    React.unmountComponentAtNode(document.getElementById('reactDemo')[0]);
    return;
} */
        this.setState({name:e.target.value});
    },render:function () {
        /* if(this.state.name == "123"){
            return <p>123</p>
        } */
        return <div>
        <HelloXianrou name={this.state.name}></HelloXianrou>
        <br/>
        <input type="text" onChange={this.handleChange} />
        </div>
    }
});
ReactDOM.render(<HelloDada></HelloDada>,document.getElementById('reactDemo'))

小结

本文主要介绍了组件的生命周期。许多方法在组件生命周期中某个确定的时间点执行。

特别感谢

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom