React Context的简述

Context

Context 设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言。
它类似vue的状态管理工具vuex,我们所接触的react中数据是通过props 属性自上而下(由父及子)进行传递的,但这种做法对于多层级父子关系的组件传值是极其繁琐的。这里主要讲解的是React 16.3之后的context版本,不在对老版本进行讲解。

context的使用流程:

1、创建context文件Mycontext,并引入createContext

import {createContext} from 'react'

2、在Mycontext文件中

const Mycontext = createContext({
    title:'MyContext title'//可以定义初始值
})

3、在需要使用context的组件Mycomponent中引入Mycontext,并且声明context,有两种声明方式,然后可以通过this.context来获取context中的内容

//引入
import Mycontext from './Mycontext'

//声明
export default class Mycomponent extends Component{
	//方式一:
	static contextType = Mycontext; 
	...
}
//方式二:
Mycomponent.contextType = MyContext;

4、Proveder和Consumer的使用
context.Provider的使用:当有多个组件嵌套时👉 父>儿>孙,用context.provider包裹父组件后,可以将context上的值传递给所有被包裹的组件树,当使用了context.Provider后我们在context中所定义的默认值将会失效,就需要在context.Provider上创建value值来进行数据传递。写法示例:

<Mycontext.Provider value={this.state}>
  <h1>parent</h1>
  <Child></Child>
</Mycontext.Provider>

context.Consumer的使用:这里通过context.Consumer可以跨组件读取某个context数据信息,在被context.Consumer包裹的元素内也可以再次使用context2.Consumer进行包裹,可以读取不同的context数据,写法示例:

<Mycontext.Consumer>
    {(context) => {
    {/*这里context代表了导出的Mycontext文件*/}
        return (
            <>
                <p>title:{context.title}</p>
            </>
        )
    }}
</Mycontext.Consumer>

5、context 对象接受一个名为 displayName 的 property,类型为字符串。React DevTools 使用该字符串来确定 context 要显示的内容。

context.displayName = "Mycontext"

在这里插入图片描述

简单实例使用

ReactDevTools 展示的结构信息:
在这里插入图片描述

context.js

import {createContext} from 'react'
//引入createContext方法来创建context

const MyContext = createContext({
	//定义默认信息
    name:'context Name',
    title:'MyContext Title'
});

export default MyContext
//导出

context2.js

import {createContext} from 'react'

const Mycontext2 = createContext({
    title:'MyContext2 title'
})

Mycontext2.displayName = "context2"

export default Mycontext2
//导出

parent.jsx

import React, { Component } from 'react'
import Child from './child.jsx'
//引入子组件
import Mycontext from './mycontext'
//引入第一个context

export default class parent extends Component {
    static contextType = Mycontext;//声明context

    constructor(){
        super()
        //在parent自身所维护的数据
        this.state={
            name:'parent Name',
            title:' parent Title'
        }
    }

    render() {
        return (
            <div>
            	{/* 通过Provider来包裹父组件,并将parent的state赋值给value,会屏蔽掉context中的默认数据 */}
                <Mycontext.Provider value={this.state}>
                    <h1>parent</h1>
                    <Child></Child>
                </Mycontext.Provider>
            </div>
        )
    }
}

child.jsx

import React, { Component } from 'react'
import Grandson from './grandson'
//引入孙子组件

export default class child extends Component {
    render() {
        return (
            <div>
                <h1>Child</h1>
                {/*显示孙子组件*/}
                <Grandson></Grandson>
            </div>
        )
    }
}

grandson.jsx

import React, { Component } from 'react'
import Mycontext from './mycontext'
//引入第一个context文件,但是数据已经被parent所代替
import Mycontext2 from './mycontext2'
//引入第二个context文件

export default class grandson extends Component {
    // static contextType = Mycontext;
    render() {
        return (
            <div>
                <Mycontext.Consumer>
                {/*通过Consumer来包裹,下面就可以通过context.的形式拿数据*/}
                    {context => {
                        return (
                            <>
                                <h3>Grandson</h3>
                                <p>name:{context.title},title:{context.name}</p>

                                <Mycontext2.Consumer>
                                {/*嵌套使用,获取不同的context文件数据*/}
                                    {context2 => {
                                        return (
                                            <>
                                                <p>title:{context2.title}</p>
                                            </>
                                        )
                                    }}
                                </Mycontext2.Consumer>
                            </>
                        )
                    }}

                </Mycontext.Consumer>
            </div>
        )
    }
}

在这里插入图片描述

计数组件的实现

我们可以通过一个简单的计数组件来查看在context中对方法的使用,了解一个context使用范式,我们可以在context文件中定义一个公共class来保存公共数据,直接通过provider来注入。
countContext.js

import React,{createContext} from 'react'

const { Provider,Consumer:CountConsumer } = createContext()
//将Provider和Consumer解构出来,并且给Consumer起别名

//定义一个公共类
class CountProvider extends React.Component{
    constructor(){
        super()
        this.state={
            count:1//计数器初始值
        }
    }

    increment=()=>{//+1操作
        this.setState({
            count:this.state.count+1
        })
    }

    decrement=()=>{//-1操作
        this.setState({
            count:this.state.count-1
        })
    }

    clickHandler=(innerHTML)=>{//按钮点击时触发的事件,根据按钮的内容来判断操作后执行相应增减方法,
        if(innerHTML==='+'){
            this.increment()

        }else{
            this.decrement()


        }
    }

    render(){
        return(
        {/*将解构出的Provider包裹,将value注入*/}
            <Provider value={{
                count:this.state.count,//暴露计数数字
                clickHandler:this.clickHandler//暴露点击事件
            }}>
            {this.props.children}//将在组件中再次包裹的内容放入
            </Provider>
        )
    }
}

export {
    CountProvider,
    CountConsumer
}
//暴露被封装的Provieder和起了别名的Consumer

Cart.jsx

import React, { Component } from 'react'
import Count from './count'
import {CountProvider} from './countContext'
//从context里面结构封装好的Provider方法

export default class cart extends Component {
    render() {
        return (
        {/*这里再次通过封装的Provider来包裹一次内容,里面的内容就会在context里面的props.children,包裹后里面就会获得context数据和方法*/}
            <CountProvider>
                <h1>购物车</h1>
                <hr/>
                <Count></Count>
            </CountProvider>
        )
    }
}

count.jsx

import React, { Component } from 'react'
import {CountConsumer} from './countContext'
//引入 Consumer,这里只是为了获取到context里面的计数数字
import Button from './Button'
//按钮组件

export default class count extends Component {
    constructor(){
        super()
    }
    render() {
        return (
            <CountConsumer>  
                {
                	// 结构出来count
                    ({count})=>{
                        return(
                            <>
                            	{/* 两个按钮 */}
                                <Button>-</Button>
                                {count}
                                <Button>+</Button>
                            </>
                        )
                    }
                }
            </CountConsumer>
        )
    }
}

我们这里触发事件的方式是

<button onClick={()=>context.someHandler()}>点老子</button>

Button.js

import React from 'react'
import {CountConsumer} from './countContext'
//将Consumer 引入,这里只要时为了获得context事件

const Button = (props)=>{
    return(
        <CountConsumer>
            {
                (context)=>{
                    return(
                    {/*给按钮添加click事件,将事件源e传入,然后将e.target.innerHTML传入方法的参数*/}
                        <button onClick={(e)=>context.clickHandler(e.target.innerHTML)}>{props.children}</button>
                    )
                }
            }
        </CountConsumer>
    )
}
export default Button

效果显示:
在这里插入图片描述

何时使用Context

Context 主要应用场景在于很多不同层级的组件需要访问同样一些的数据。请谨慎使用,因为这会使得组件的复用性变差。如果用组件组合可以解决的问题,就不要使用 Context 。

使用 context 的通用的场景包括管理当前的 locale,theme,或者一些缓存数据。

总结

总结部分摘自:https://blog.csdn.net/Charissa2017/article/details/105746685

  • React.createContext(defaultValue) 创建一个 Context 对象。
  • Class.contextType,挂载在 class 上的 contextType 属性会被赋值为一个 Context 对象。这能让你使用 this.context 来消费最近的 Context 上的数据。你可以在任何生命周期中访问到它,包括 render 函数中。
  • Context.Provider,接收一个 value 属性,传递给消费组件。一个 Provider 可以和多个消费组件有对应关系。多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据。
  • Context.Consumer,是函数作为子元素(function as a child)这种做法。这个函数参数接收当前的 context 值,返回一个 React 节点。传递给函数的 value 等同于往上组件树离这个 context 最近的 Provider 提供的 value 值。如果没有对应的 Provider,value 参数等同于传递给 createContext() 的 defaultValue。
  • Context.displayName,浏览器中调试用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值