首页 > 技术文章 > context和optimize优化

guapitomjoy 2021-09-03 16:49 原文

3. context和optimize优化

3.1 context

context用于祖孙组件之间的传参

import React, {Component} from 'react';
import './index.css'

// 创建一个context组件,供传递数据使用
const MyContext = React.createContext()

class A extends Component {

    state = {username: 'cxk', age:18}

    render() {
        const {username} = this.state
        return (
            <div className='parent'>
                <h3>我是A组件</h3>
                <h4>我的用户名是:{username}</h4>

                {/* 固定写法*/}
                <MyContext.Provider value={this.state}>
                    <B/>
                </MyContext.Provider>
            </div>
        );
    }
}

//第一种方式:仅适用于类组件
class B extends Component {
    // 声明使用contex,才能获取到祖组件传递的数据
    static contextType = MyContext

    render() {
        // 读取context中的value数据
        // console.log(this.context)
        return (
            <div className='child'>
                <h3>我是B组件</h3>
                <h4>我从A接收到的用户名是:{this.context.username}</h4>
                <C/>
            </div>
        );
    }
}

// class C extends Component {
//     // 声明使用contex,才能获取到祖组件传递的数据
//     static contextType = MyContext
//
//     render() {
//         // console.log(this)
//         return (
//             <div className='grand'>
//                 <h3>我是C组件</h3>
//                 <h4>我从A收到的用户名是:{this.context.username}, 年龄是{this.context.age}</h4>
//             </div>
//         );
//     }
// }

//第二种方式: 函数组件与类组件都可以
function C() {
    return (
            <div className='grand'>
                <h3>我是C组件</h3>
                <h4>我从A收到的用户名是:
                     {/*函数式组件使用context取值, 类式组件也可以*/}
                     <MyContext.Consumer>
                         {
                             (value)=>{ 	// value就是context中的value数据
                                 return `${value.username} 年龄是:${value.age}`
                             }
                         }
                     </MyContext.Consumer>
                </h4>
            </div>
        );
}


export default A;

注意

在应用开发中一般不用context, 一般都用它的封装react插件

3.2 optimize优化

Component的2个问题

  1. 只要执行setState(),即使不改变状态数据, 组件也会重新render() ==> 效率低

  2. 只当前组件重新render(), 就会自动重新render子组件,纵使子组件没有用到父组件的任何数据 ==> 效率低

效率高的做法

只有当组件的state或props数据发生改变时才重新render()

原因

Component中的shouldComponentUpdate()总是返回true

解决

办法1: 
	重写shouldComponentUpdate()方法
	比较新旧state或props数据, 如果有变化才返回true, 如果没有返回false
办法2:  
	使用PureComponent
	PureComponent重写了shouldComponentUpdate(), 只有state或props数据有变化才返回true
	注意: 
		只是进行state和props数据的浅比较, 如果只是数据对象内部数据变了, 返回false  
		不要直接修改state数据, 而是要产生新数据
项目中一般使用PureComponent来优化
import React, {Component, PureComponent} from 'react';
import './index.css'

class Parent extends PureComponent {

    state = {carName: 'BMW', stus:['a','b','c']}

    addStu = () => {
        // 错误
/*        const {stus} = this.state
        stus.unshift('老王')
        this.setState({stus})*/

        // 正确
        const {stus} = this.state
        this.setState({stus:['老王',...stus]})

    }

    changeCar = () => {
        // this.setState({})

        // 使用PureComponent后不能在原来得对象修改,不然就视为没有更新 ,所以点击并没有触发render,
        // const obj = this.state
        // obj.carName = 'AMG'
        // this.setState(obj)

        // 正确
        this.setState({carName: 'AMG'})

    }

    // shouldComponentUpdate(nextProps, nextState, nextContext) {
    //     console.log(nextProps,nextState)
    //     console.log(this.props,this.state)
    //     return !(nextState.carName === this.state.carName)
    // }

    render() {
        console.log('parent---render')
        const {carName} = this.state
        return (
            <div className='parent'>
                <h3>我是Parent组件</h3>
                <span>{this.state.stus}&nbsp</span>
                <span>我的车现在是{carName}</span>
                <button onClick={this.changeCar}>点我换车</button>
                <button onClick={this.addStu}>添加一个老王</button>
                <Child carName={carName}/>
            </div>
        );
    }
}
class Child extends PureComponent {

    // shouldComponentUpdate(nextProps, nextState, nextContext) {
    //     // console.log(nextProps,nextState)
    //     // console.log(this.props,this.state)
    //     return !(nextProps.carName === this.props.carName)
    // }

    render() {
        // 使用PureComponent后若子组件的数据没更新就不会触发render
        console.log('child---render')
        return (
            <div className='child'>
                <h3>我是Child组件</h3>
                <span>我接到的车是{this.props.carName}</span>
            </div>
        );
    }
}

export default Parent;

推荐阅读