React(十一)- React拓展:Fragment、Context及PureComponent

React(十一)- React拓展:Fragment、Context及PureComponent

  • 一. Fragment拓展
  • 二. Context拓展
    • 2.1 总结
  • 三. PureComponent拓展
    • 3.1 修改方案1
    • 3.2 修改方案2

React系列文章导航

一. Fragment拓展

案例如下:

jsx语法中,render()里面最外层的标签,同级的不能有两个,如下
React(十一)- React拓展:Fragment、Context及PureComponent_第1张图片
可以使用Fragment包起来,来解决上述问题:
React(十一)- React拓展:Fragment、Context及PureComponent_第2张图片

二. Context拓展

Context,一种组件通信方式,常用于祖组件子类组件之间的通信。

案例如下:

首先,页面效果如图:
React(十一)- React拓展:Fragment、Context及PureComponent_第3张图片
项目结构:
Demo组件:

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

const MyContext = React.createContext()
const { Provider, Consumer } = MyContext
export default class A extends Component {
    state = { username: 'tom', age: 18 }

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

class B extends Component {
    render() {
        return (
            <div className="child">
                <h3>我是B组件</h3>
                <C />
            </div>
        )
    }
}
// 类式组件的用法
// class C extends Component {
//     // 声明接收context
//     static contextType = MyContext
//     render() {
//         const { username, age } = this.context
//         return (
//             
//

我是C组件

//

我从A组件中接收到的用户名是:{username}

//

我从A组件中接收到的年龄是:{age}

//
// ) // } // } // 函数式组件的用法,必须使用到Consumer标签 function C() { return ( <div className="grand"> <h3>我是C组件</h3> <h4>我从A组件中接收到的用户名是: <Consumer> {value => `${value.username},年龄是${value.age}`} </Consumer> </h4> </div> ) }

index.css文件:

.parent{
    width: 500px;
    background-color: orange;
    padding: 8px;
}
.child{
    width: 100%;
    background-color: skyblue;
    padding: 8px;
}
.grand{
    width: 400px;
    background-color: gray;
    padding: 10px;
}

从代码结构来看,A是父类,B是A的子类,C是B的子类,哪怕B没有传递对应的属性,C依旧可以获取到A类的值。

2.1 总结

  1. 创建Context容器对象:const xxx= React.createContext()

  2. 渲染子组件时,外面包裹xxx.Provider 标签,通过value属性给后代组件传递数据:

<xxxContext.Provider value={数据}>
	<子组件/>
</xxxContext.Provider>
  1. 后代组件读取数据:并且只要用xxx.Provider 包裹的一个子组件,那么该子组件以及其后代都能够直接获取到对应的数据,只需要声明接收context即可。
//第一种方式:仅适用类组件 
// 声明接收context,contextType命名是固定的
static contextType = xxxContext 
// 读取context中的value数据
this.context 
  
//第二种方式: 函数组件与类组件都可以
<xxxContext.Consumer>
  {
    value => ( // value就是context中的value数据
      要显示的内容
    )
  }
</xxxContext.Consumer>

三. PureComponent拓展

这一小节主要来说说组件的优化,其实Component有2个问题

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

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

效率高的情况是怎么样的呢?就是:只有当组件的stateprops数据发生改变时才重新调用render(),即不会收父组件以及setState()方法的影响。

案例1:

import React, { Component } from 'react'
import './index.css'
export default class Parent extends Component {
    state = { carName: '奔驰' }

    changeCar = () => {
        this.setState({ carName: '宝马' })
    }

    render() {
        console.log('Parent----render')
        const {carName} = this.state
        return (
            <div className="parent">
                <h3>我是Parent组件</h3>
                <span>车名:{carName}</span><br/>
                <button onClick={this.changeCar}>换车</button>
                <Child carName="奥拓"/>
            </div>
        )
    }
}

class Child extends Component {
    render() {
        console.log('Child----render')
        return (
            <div className="child">
                <h3>我是Child组件</h3>
                <span>我接收到的车是:{this.props.carName}</span>
            </div>
        )
    }
}

页面效果:
React(十一)- React拓展:Fragment、Context及PureComponent_第4张图片

点击换车按钮后可以发现:子组件也重新调用了render()进行了渲染。

React(十一)- React拓展:Fragment、Context及PureComponent_第5张图片

那么如何对上述问题进行修改呢?

3.1 修改方案1

重写shouldComponentUpdate()方法:

import React, { Component } from 'react'
import './index.css'
export default class Parent extends Component {
    state = { carName: '奔驰' }

    changeCar = () => {
        this.setState({ carName: '宝马' })
    }



    render() {
        console.log('Parent----render')
        const { carName } = this.state
        return (
            <div className="parent">
                <h3>我是Parent组件</h3>
                <span>车名:{carName}</span><br />
                <button onClick={this.changeCar}>换车</button>
                <Child carName="奥拓" />
            </div>
        )
    }
}

class Child extends Component {

    shouldComponentUpdate(nextProps, nextState) {
        return !this.props.carName === nextProps.carName
    }

    render() {
        console.log('Child----render')
        return (
            <div className="child">
                <h3>我是Child组件</h3>
                <span>我接收到的车是:{this.props.carName}</span>
            </div>
        )
    }
}

3.2 修改方案2

引用PureComponent

import React, { PureComponent } from 'react'
import './index.css'
export default class Parent extends PureComponent {
    state = { carName: '奔驰' }

    changeCar = () => {
        this.setState({ carName: '宝马' })
    }

    render() {
        console.log('Parent----render')
        const { carName } = this.state
        return (
            <div className="parent">
                <h3>我是Parent组件</h3>
                <span>车名:{carName}</span><br />
                <button onClick={this.changeCar}>换车</button>
                <Child carName="奥拓" />
            </div>
        )
    }
}

class Child extends PureComponent {
    render() {
        console.log('Child----render')
        return (
            <div className="child">
                <h3>我是Child组件</h3>
                <span>我接收到的车是:{this.props.carName}</span>
            </div>
        )
    }
}

页面效果:
React(十一)- React拓展:Fragment、Context及PureComponent_第6张图片

点击换车按钮后可以发现:子组件并没有调用render()
React(十一)- React拓展:Fragment、Context及PureComponent_第7张图片

原理如下:

PureComponent重写了shouldComponentUpdate(),,只有stateprops数据有变化才返回true

注意:

  1. 只是进行stateprops数据的浅比较,如果只是数据对象内部数据变了,返回false
  2. 不要直接修改state数据,,而是要产生新数据。

你可能感兴趣的:(React)