React-Context

React-Context

复习react中,对以前迷糊的点重新get一下

API

react官方文档的context中存在这么几个api

  • React.createContext
  • Context.Provider
  • Class.contextType
  • Context.Consumer
  • Context.displayName
Reacr.createContext

创建一个 Context 对象。当 React 渲染一个订阅了这个 Context 对象的组件,这个组件会从组件树中离自身最近的那个匹配的 Provider 中读取到当前的 context 值。

const MyContext = React.createContext(defaultValue);

我们可以创建一个看看里面是啥

let theme = {
    light:{
        title:'光明'
    },
    dark:{
        title:'黑暗'
    }
}
let Context = React.createContext(theme.dark)
//打印之后的结果
/*$$typeof: Symbol(react.context)
Consumer: {$$typeof: Symbol(react.context), _context: {…}, _calculateChangedBits: null, …}
Provider: {$$typeof: Symbol(react.provider), _context: {…}}
_calculateChangedBits: null
_currentRenderer: {}
_currentRenderer2: null
_currentValue: {title: "黑暗"}
_currentValue2: {title: "黑暗"}*/
//我们会看见里面包含到了context里面的两个api-》Consumer,Provider
Context.Provider
<MyContext.Provider value={/* 某个值 */}>

每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化。

Provider 接收一个 value 属性,传递给消费组件。一个 Provider 可以和多个消费组件有对应关系。多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据。

Class.contextType

挂载在 class 上的 contextType 属性会被重赋值为一个由 React.createContext() 创建的 Context 对象。这能让你使用 this.context 来消费最近 Context 上的那个值。你可以在任何生命周期中访问到它,包括 render 函数中

Class.Consumer

这里,React 组件也可以订阅到 context 变更。这能让你在函数式组件中完成订阅 context。

这需要函数作为子元素(function as a child)这种做法。这个函数接收当前的 context 值,返回一个 React 节点。传递给函数的 value 值等同于往上组件树离这个 context 最近的 Provider 提供的 value 值。如果没有对应的 Provider,value 参数等同于传递给 createContext()defaultValue

最后一个我确实不太想写。。。关于react-devtools的一个显示的名字。。

以上我们大概可以get到怎么用了,那我们可以练手了

  1. 先走一个context
import React from 'react'
let theme = {
    light:{
        title:'光明'
    },
    dark:{
        title:'黑暗'
    }
}
let Context = React.createContext(theme.dark)
export {
    theme,
    Context
}
  1. 走一个最外层组件
import React from 'react'
import Third from './Third'
import {theme,Context} from './context.js'
class App extends React.Component {
    constructor(props){
        super(props)
        this.state = { 
            list:[1,2,3,4],
            theme:theme.dark
        }
    }
    changeTheme=()=>{
      this.setState({
        ...this.state,
        theme:this.state.theme.title === '光明' ? theme.dark : theme.light
      })
    }
    render() {
      return (
       <Context.Provider value={this.state}>
        <div>第一级组件</div>
        <Toolbar></Toolbar>
        <button onClick={this.changeTheme}>变大变小变漂亮</button>
       </Context.Provider>
      )
    }
}
class Toolbar extends React.Component{
  constructor(){
    super()
    this.state={
      title : test2.dark
    }
  }
  render(){
    return (
      <>
        <div>第二级组件</div>
        <Third />
      </>
    );
  }
}
export default App
  1. 走一个孙子组件
import React, { Component } from 'react'
import { Context} from './context.js'
class Third extends Component {
    static contextType = Context
    render() {
        console.log(this.context)
        return (
            <>
                <div>{this.context.theme.title}</div>
                <ul>
                    {
                        this.context.list.map((value, key) => {
                            return (
                                <li key={key}>{`${key} - ${value} - ${this.context.theme.title}`}</li>
                            )
                        })
                    }
                </ul>
                <Context.Consumer>
                    {
                        (value) => {  
                          console.log(value,item2)
                          value.list.map((item, key) => {
                          return (
                           <li key={key}>{`${key} - ${item} - ${value.theme.title}`}</li>
                          )
                         })
                    }
                </Context.Consumer>
            </>
        )
    }
}
export default Third
//这样就能生成一个li列表
0-1-黑暗
1-2-黑暗
2-3-黑暗
3-4-黑暗
//并且点击按钮之后会切换光明和黑暗文字

以上就是context的基本使用,唉其实网上都有差不多的,主要是以下的问题促使我写这篇东西的

1、 createContext的时候会有一个defaultvalue,然后再provider的时候会有一个value,两者的关系是什么呢?

我们把creactContext中的defaultvalue删除的时候会发现并不影响程序运行,那么defaultvalue到底有什么用呢,和provider上的value有什么联系呢?

只有当组件所处的树中没有匹配到 Provider 时,其 defaultValue 参数才会生效。这有助于在不使用 Provider 包装组件的情况下对组件进行测试。注意:将 undefined 传递给 Provider 的 value 时,消费组件的 defaultValue 不会生效。

以上是官网的解释,ok那就是当我们的provider没有value的时候,privider传递的就是defaultvalue

2、多个context怎么写?

<Context1.Consumer>
    {
        (value) => {
            return <Context2.Consumer>
            {
               item2 => {
                console.log(value,item2)
                value.list.map((item, key) => {
                    return (
                        <li key={key}>{`${key} - ${item} - ${value.theme.title}`}</li>
                    )
                })
               }
            }
          </Context2.Consumer>
        }
     }
</Context1.Consumer>

3、contextTypeConsumer都是可以拿到context进行组件渲染,那么他们有什么区别?

其实当时我也很迷惑,并且网上我并没有搜到答案,于是当我继续按照文档过多个context的时候发现了端倪,在官网上多个context的例子只是用Consumer来写的,并没有用到contextType,并且我自己尝试的时候发现如果渲染多个的话contextType我是没有想到方法。所以我想区别大概是

  • contextType并不能对应对多个context(主)
  • Consumer的写法更贴近组件的概念(辅)

注意

因为 context 会使用参考标识(reference identity)来决定何时进行渲染,这里可能会有一些陷阱,当 provider 的父组件进行重渲染时,可能会在 consumers 组件中触发意外的渲染。举个例子,当每一次 Provider 重渲染时,以下的代码会重渲染所有下面的 consumers 组件,因为 value 属性总是被赋值为新的对象:

class App extends React.Component {
  render() {
    return (
      <MyContext.Provider value={{something: 'something'}}>
        <Toolbar />
      </MyContext.Provider>
    );
  }
}

为了防止这种情况,将 value 状态提升到父节点的 state 里:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: {something: 'something'},
    };
  }

  render() {
    return (
      <Provider value={this.state.value}>
        <Toolbar />
      </Provider>
    );
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值