美文网首页React
React状态(State)和生命周期

React状态(State)和生命周期

作者: 宁小姐的慢时光 | 来源:发表于2018-07-08 22:30 被阅读81次

    主要记录React的简单使用,便于查阅。

    • 引入react库
    • 组件(Components)
    • 状态(State)
    • 生命周期

    一、引入react库

    三种引入方式,分别如下:

    • 用<script>标签加载react文件
    • 在npm下使用ES6(推荐)
      有node环境,如果没有node环境,先安装nodejs,在nodejs官网https://nodejs.org/en/下载需要的版本,进行安装。
      然后在项目中安装react,npm install react --save-dev
      最后在文件中引入react,import React from 'react'
    • 在npm下使用ES5
      同样需要node环境,安装react,同上
      最后在文件中引入react,var React = require('react')

    引入react后,就会有React这个全局变量,React是React库的入口,顶级API都在React这个全局变量上,接下来就就可以使用React的API编写代码了。


    二、组件(Components)

    组件可以将用户界面分成独立的,可复用的小部件,并且可以对每个部件进行单独的设计。
    React可以将组件定义为类或函数,定义为类组件会提供更多功能,所以常定义为类组件,要定义组件类,需要扩展React.Component,如下:

    class Welcome extends React.Component {
      render() {
        return <h1>Hello, {this.props.name}</h1>;
      }
    }
    

    注:必须在React.Component子类中定义render()方法。


    三、状态(State)和生命周期

    React把组件看成是一个状态机,通过与用户的交互,实现不同状态,然后渲染UI,让用户界面和数据保持一致。
    状态是私有的,完全受控于当前组件。
    React里,只需要更新组件的state,然后根据新的state重新渲染用户界面(不用操作DOM)。
    如下:

    class Clock extends React.Component {
      constructor(props) {
        super(props);
        this.state = {date: new Date()};
      }
    
      render() {
        return (
          <div>
            <h1>Hello, world!</h1>
            <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
          </div>
        );
      }
    }
    

    如何定义State

    State必须能代表一个组件UI呈现的完整状态集,即组件的任何UI改变,都可以从State的变化中反映出来;同时,State还必须是代表一个组件UI呈现的最小状态集,即State中的所有状态都是用于反映组件UI的变化,没有任何多余的状态,也不需要通过其他状态计算而来的中间状态。

    组件中用到的一个变量是不是应该作为组件State,可以通过下面的4条依据进行判断:

    • 这个变量是否是通过Props从父组件中获取?如果是,那么它不是一个状态。
    • 这个变量是否在组件的整个生命周期中都保持不变?如果是,那么它不是一个状态。
    • 这个变量是否可以通过其他状态(State)或者属性(Props)计算得到?如果是,那么它不是一个状态。
    • 这个变量是否在组件的render方法中使用?如果不是,那么它不是一个状态。这种情况下,这个变量更适合定义为组件的一个普通属性,例如组件中用到的定时器,就应该直接定义为this.timer,而不是this.state.timer。
    • 注意:不是组件中用到的所有变量都是组件的状态!当存在多个组件共同依赖一个状态时,一般的做法是状态上移,将这个状态放到这几个组件的公共父组件中。

    如何使用state

    1、 在构造函数(constructor)中初始化state
    2、在render中使用state的值
    3、用setState修改state,从而触发DOM重新渲染
    注意:不要直接修改state,这样并不会重新触发render,如:this.state.date = '2018年7月8日'
    用setState修改,如:this.setState({date: ' 2018年7月8日'})
    4、 setState方法是异步的
    调用setState时,组件state不会立即改变,只是把要修改的状态放入事件队列中,react会优化真正的执行时机,并且处于本身的性能原因,可能会对此setState的状态修改合并成一次状态修改。
    因此不要依靠当前的state计算下一个state,因为当真正执行状态修改时,依赖的this.state并不能保证是最新的state,因为react本身会把多次state合并成一次,这时this.state可能还是setState前的state。
    如果需要使用当前state计算新的state,正确用法:

    //preState: 当前的最新状态的前一个状态
    //props: 当前最新的props
    this.setState((preState,props)=>({counter:preState.quantity+1}))
    

    如果要在setState方法后直接获取更新后的state值,需要在setState中传入第二个参数,传入一个回调函数,正确写法为:

    this.setState({date: ' 2018年7月8日'},  () => {console.log(this.state.date)})
    

    5、state的更新是一个合并的过程
    当调用setState()修改组件状态时,只需要传入发生变化的state,不是完整的state,因为组件state的更新是一个合并的过程,如:一个组件的状态为:

    this.state({
    title: 'React',
    content: 'React is an wondeful JS library'
    })
    

    当只需要修改title时,只需要将修改的title传给setState即可:

    this.setState({title: 'ReactJs'})
    

    react会合并最新的title到原来的状态,同时保留原来的content。
    6、state与不可变对象
    React官方把state当成不可变对象,一方面是直接修改this.state组件不会重新render,通过setState修改state才会render;另一方面,state中包含的所有状态都应该是不可变对象。
    当state当中的某一个状态发生变化时,应该重新创建这个状态对象,不是直接修改原来的state状态。
    状态类型可以分为三种情况:

    • 状态类型为不可变类型(number, string, boolean, null, undefined)
      状态为不可变类型时,直接给要修改的状态赋新值即可。
    • 状态类型为数组
      假如有一个数组类型的状态books,当想给books中增加一本书时,可以使用数组的concat方法或者es6的扩展运算符
    //方法一:使用preState,concat创建新数组
    this.setState((preState) => ({
      books: preState.books.concat(['React'])
    }))
    //方法二:使用ES6扩展运算符
    this.setState(preState => ({
      books: [...preState, 'React']
    }))
    

    当从books中截取部分元素作为新状态时,可以使用数组的slice方法:

    this.setState(preState => ({
      books: preState.books.slice(1, 3)
    }))
    

    当从books中过滤部分元素作为新状态时,可以使用filter方法:

     this.setState(preState => ({
      books: preState.books.filter(item => item !== 'React')
    }))
    
    • 状态的类型是普通对象
    //使用es6的Object.assign()方法
     this.setState(preState => {
      onwer: Object.assign({}, preState.onwer, {name: 'Jason'})
    })
    
    //使用对象扩展运算符
     this.setState(preState => {
      owner: {...preState.owner, name: ''Jason}
    })
    

    注意:创建新的状态对象关键是,避免使用会直接修改原对象的方法,而是使用可以返回一个新对象的方法。可以使用一些Immutable的JS库,如Immutable.js,实现类似的效果。

    为什么React推荐组件的状态是不可变对象?

    一方面是因为不可变对象方便管理和调试,另一方面是出于性能考虑,当对象组件状态都是不可变对象时,在组件的shouldComponentUpdate方法中,仅需要比较状态的引用就可以判断状态是否真的改变,从而避免不必要的render调用


    四、生命周期

    React定义了组件的生命周期,主要分为三个过程:

    • 挂载过程(Mount),组件第一次在DOM树渲染的过程
    • 更新过程(Update),组件被重新渲染的过程
    • 卸载过程(Unmount),组件从DOM树中删除的过程
      执行这3个过程的调用函数就是声明周期函数。

    挂载过程
    该过程会依次调用如下函数:

    • constructor():ES6类的构造函数,接收两个参数props, context,可以获得父组件传下来的props(为了初始化state和绑定this)
    • componentWillMount():在组件被挂载前调用,只执行一次
    • render():渲染组件
    • componentDidMount():组件挂载后调用,这时已经生成了真实的DOM节点,只执行一次,一般在这里发送异步请求,操作DOM

    更新过程
    当组件的props或者state改变时会触发组件的更新过程
    该过程会依次执行如下函数:

    • componentWillReceiveProps(nextProps):在接受父组件改变后的props需要重新渲染组件时用到的比较多,初始化时不调用
    • shouldComponentUpdate(nextProps,nextState):判断组件是否应该重新渲染,默认是true,当props或者state改变时调用(父组件重新渲染),初始化时不调用,返回boolean。true表示继续执行render方法,false表示跳过本次渲染。在这里可以优化react性能。
    • componentWillUpdate(nextProps,nextState):shouldComponentUpdate返回true后,componentWillUpdate会被调用

    卸载过程
    componentWillUnmount:将组件从DOM树移除,防止内存溢出

    测试生命周期执行顺序:

    class App extends React.Component {
        constructor(props){
            super(props)
            console.log("---初始化组件---")
        }
        componentWillMount(){
            console.log("---组件挂载前---")
        }
        componentDidMount(){
            console.log("---组件挂载后---")
        }
        componentWillReceiveProps(nextProps){
            console.log("---父组件重新渲染---")
        }
        shouldComponentUpdate(nextProps,nextState){
            console.log("---组件接受到重绘状态---")
            if(this.props != nextProps || this.state != nextState)
            return true
        }
        render() {
            console.log("---组件渲染---")
        }
    }
    

    参考文档:
    http://www.css88.com/react/docs/getting-started.html
    https://www.jianshu.com/p/c6257cbef1b1

    相关文章

      网友评论

        本文标题:React状态(State)和生命周期

        本文链接:https://www.haomeiwen.com/subject/ghaouftx.html