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

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

React系列文章导航

一. Fragment拓展

案例如下:

jsx语法中,render()里面最外层的标签,同级的不能有两个,如下
在这里插入图片描述
可以使用Fragment包起来,来解决上述问题:
在这里插入图片描述

二. Context拓展

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

案例如下:

首先,页面效果如图:
在这里插入图片描述
项目结构:
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 (
//             <div className="grand">
//                 <h3>我是C组件</h3>
//                 <h4>我从A组件中接收到的用户名是:{username}</h4>
//                 <h4>我从A组件中接收到的年龄是:{age}</h4>
//             </div>
//         )
//     }
// }

// 函数式组件的用法,必须使用到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>
        )
    }
}

页面效果:
在这里插入图片描述

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

在这里插入图片描述

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

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>
        )
    }
}

页面效果:
在这里插入图片描述

点击换车按钮后可以发现:子组件并没有调用render()
在这里插入图片描述

原理如下:

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

注意:

  1. 只是进行stateprops数据的浅比较,如果只是数据对象内部数据变了,返回false
  2. 不要直接修改state数据,,而是要产生新数据。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zong_0915

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值