React生命周期和类组件复习

1 创建Class组件

  • ES5方式(过时)

    import React from 'react'
    
    const A = React.createClass({
    	render(){
    		return(
    			<div>hi</div>
    		)
    	}
    })
    
    export default A
    复制代码
  • ES6方式

    import React from 'react'
    
    class B extends React.Component {
    	constructor(props){
    		super(props);
    	}
    	render() {
    		return (
    			<div>hi</div>
    		)
    	}
    }
    
    export default B
    复制代码

2 Props外部数据

  • 传入props给B组件

    import React from 'react'
    
    class Parent extends React.Component {
      // 初始化 this.props就是外部数据对象的地址了
    	constructor(props){
    		super(props);
        // 父元素的state作为props
        this.state = {name : 'frank'}
    	}
      onClick = () => {}
    	render() {
    		return (
          {/* 把this.state.name作为B的外部数据 */}
    			<	B name = {this.state.name}
            {/* 把外面的onClick函数传给B的onClick,此处的onClick是一个回调 */}
            	onClick = {this.onClick}>hi</B>
    		)
    	}
    }
    // {name: 'frank', onClick: ... , children: 'hi'}
    export default B
    复制代码
  • 读props

    class B extends React.Component{
    	constructor(props){
    		super(props);
    	}
      render(){
        return <div onClick = {this.props.onClick}>
        	{this.props.name}
          	<div>
          		{this.props.children}
          	</div>
        </div>
      }
    }
    // 通过 this.props.xxx读取
    复制代码
  • 写props

    原则上应该由数据的主人对数据进行更改

  • props的作用

    • 接受外部数据

      只能读不能写

      外部数据由父组件传递

    • 接受外部函数

      在恰当的时机,调用该函数

      该函数一般是父组件的函数

3 State 内部数据

  • 初始化State

    class B extends React.Component{
    	constructor(props){
    		super(props);
    		this.state = {
    			user:{name : 'frank', age : 18}
    		}
    	}
    	render() {}
    }
    复制代码
  • 读写State

    • 读用this.state

      this.state.xxx.yyy.zzz
      复制代码
    • 写用this.setState(???, fn)

      1. this.setState(newState, fn)

        注意setState不会立刻改变this.state,会在当前代码运行完后,再去更新this.state,从而触发UI更新

      2. this.setState((state,props) => newState,fn)

        易于理解,fn会在写入成功后执行

      onClick = () => {
          this.setState({
              x: this.state.x + 1
          })
      }
      
      onClick2 = () => {
          this.setState((state) => ({x: state.x + 1}))
      }
      复制代码

4 生命周期

  • 类比如下代码

    let div = document.createElement('div')
    // 这是div的create/construct的过程
    div.textContent = 'hi'
    // 这是初始化state
    document.body.apppendChild(div)
    // 这是div的mount过程
    div.textContent = 'hi2'
    // 这是div的update过程
    div.remove()
    // 这是div的numount过程
    复制代码
  • 生命周期函数列表

    constructor() – 在这里初始化state

    static getDerivedStateFroProps()

    shouldComponentUpdate() – return false 阻止更新

    render() – 创建虚拟DOM

    getSnapshotBeforeUpdate()

    componentDidMount() – 组件已出现在页面

    componentDidUpdate() – 组件已更新

    componentWillUnmount() – 组件将死

    static getDerivedStateFromError()

    componetDidCatch()

4.1 constructor

  • 用途

    • 初始化props

    • 初始化state,但此时不能调用setState

    • 用来写bind this

      constructor(){
      	...
      	this.onClick = this.onClick.bind(this)
      }
      复制代码

      新语法

      onClick = () => {}
      constructor(){...}
      复制代码
  • 可不写

4.2 shouldComponentUpdate

  • 用途

    返回true表示不阻止UI更新

    返回false表示阻止UI更新

  • 面试常问

    • shouldComponentUpdate有什么用
    • 答:它允许我们手动判断是否要进行组件更新,我们可以根据应用场景灵活地设置返回值,以避免不必要的更新
  • 示例

    import React from 'react'
    
    class App extends React.PureComponent {
    //  1.初始化
        constructor(props) {
            super(props)
            // 2.设置变量
            this.state = {
                n: 1
            }
        }
        // 3. 让n+1又-1,UI不会变化,但是每次点击按钮都render了一次
        onClick = () =>{
            this.setState(state => ({
                n: state.n + 1
            }))
            this.setState(state => ({
                n: state.n - 1
            }))
            // {n:1} 和 {n:1} 是不同的对象,但值一样
        }
        // 比较新旧n是否改变
        // shouldComponentUpdate(nextProps, nextState) {
        //     return nextState.n !== this.state.n;
            // 返回true不阻止UI更新
            // 返回false阻止UI更新
        // }
    
        render() {
            console.log('render 了一次')
            return(
                <div>App
                    <div>
                        {this.state.n}
                        <button onClick={
                            this.onClick
                        }>+1</button>
                    </div>
                </div>
            )
        }
    }
    
    export default App;
    复制代码

图片.png

  • 可用PureComponent代替这个钩子

    class App extends React.PureComponent{}
    复制代码
    • PureComponent 会在 render 之前对比新 state 和旧 state 的每一个 key,以及新 props 和旧 props 的每一个 key。
    • 如果所有 key 的值全都一样,就不会 render;如果有任何一个 key 的值不同,就会 render。

4.3 render

  • 用途

    展示视图return (<div>...</div>)

    只能有一个根元素,如果有两个根元素,就要用<React.Fragment>包起来,可以缩写成<></>

  • 技巧

    • render里面可以写if. else
    • render里面可以写?:表达式
    • render里面不能直接写for循环,需要用数组
    • render里面可以写 array map(循环)
render() {
        return (
            <>
                {this.state.n % 2 === 0 ?
                    <div>偶数</div> : <span>奇数</span>
                }
                <button onClick={this.onClick}>+1</button>
            </>
        )
    }
复制代码

4.4 componentDidMount

组件已经挂载了

  • 用途
    • 在元素插入页面后执行代码,这些代码依赖DOM,比如想获取div的高度,最好在这写
    • 此处可以发起加载数据的AJAX请求(官方推荐)
    • 首次渲染会执行次钩子
  • 示例
import React from 'react'

class App extends React.PureComponent {
    divRef = undefined

    constructor(props) {
        super(props)

        this.state = {
            n: 1,
            width: undefined
        }
        this.divRef = React.createRef()
    }


    componentDidMount() {
        const div = this.divRef.current
        const {width} = div.getBoundingClientRect()
        this.setState({width})
    }

    render() {
        return (
            <div ref={this.divRef}>hello,{this.state.width}px</div>
        )
    }
}

export default App;

复制代码

4.5 componentDidUpdate

  • 用途
    • 在视图更新后执行代码
    • 此处也可以发起AJAX请求,用于更新数据
  • 注意
    • 首次渲染不会执行此钩子
    • 在此处setState可能会引起无限循环,除非放在if里
    • shouldComponentUpdate返回false,则不触发此钩子

4.6 componentWillUnmount

  • 用途

    组件将要被移出页面然后被销毁时执行代码

    unmount过的组件不会再次mount

  • 举例

    • 如果在componentDidMount里面监听了window scroll,那么就要在componentWillUnmount里取消监听

    • 如果在componentDidMount里面创建了AJAX请求,那么就要在componentWillUnmount里取消请求

4.7 生命周期总结

图片.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享