React

React状态(State)和生命周期

2018-07-08  本文已影响81人  宁小姐的慢时光

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

一、引入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条依据进行判断:

如何使用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状态。
状态类型可以分为三种情况:

//方法一:使用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定义了组件的生命周期,主要分为三个过程:

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

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

卸载过程
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

上一篇下一篇

猜你喜欢

热点阅读