React Context(执行上下文) 的那些事儿

Context是16.3.0正式确定的API,在这之前Context是以实验性API的身份存在。 本文没有关于16.3.0之前版本中Context相关API的解释
核心逻辑:发布订阅模式
核心概念:Context(执行上下文)、Provider(发布者)、Consumer(订阅者)

Context 解决什么问题

Context 设计用来解决祖先组件向后代组件传递数据的问题(prop drilling)。为跨层级的组件搭建一座桥梁。
举个例子:用户登录之后,很多组件需要拿到用户相关信息,如果按照prop传递的方式获取,会变得异常繁琐,而且很难判断数据的真正来源


而如果使用Context,则在Provider的后代组件的任意位置,都可以Consumer数据

有同学可能要问,使用`redux`不也可以解决这个问题吗?答案是:你说的对。不过redux本身就是通过context实现的。

如何使用 Context

步骤 1. 通过createContext创建Context 2. 使用Context.Provider组件发布数据(通过给Context.Provider传递value属性)。 3. Context.Provider的所有后代组件,都可以通过Context.Consumer消费数据

Demo: 创建一个用于存放用户数据的Context

// 从react库中引入createContext方法
import React, { Component, createContext } from 'react'
// 通过createContext方法创建用于存放用户数据的Context类
const UserContext = createContext()
// 通过UserContext的属性Provider(组件)发布用户数据
// 传递给Provider的value属性的值可以是任意数据类型,甚至是函数
class App extends Component {
  state = {
    user: {
      name: 'abc',
    },
  }
  render() {
    const {
      user,
    } = this.state
    return (
      <UserContext.Provider value={user}>
        <UseUserInfoComponent />
      </UserContext.Provider>
    )
  }
}
// 通过UserContext的属性Consumer(组件)消费用户数据
// Consumer的子组件必须是一个function,通过function的参数接收顶层传入的数据
class UseUserInfoComponent extends Component {
  render() {
    return (
      <UserContext.Consumer>
        {
          context => (
            <div>
              <p>{context.name}</p>
            </div>
          )
        }
      </UserContext.Consumer>
    )
  }
}
复制代码

使用中需要注意的点

  • 调用creatContext时可以传入默认值,但该值不是Provider的默认值,而是作为Consumer的默认值,仅当没有Provider的时候才生效
const UserContext = createContext({
  user: {
    name: 'max',
  },
})

class App extends Component {
  render() {
    return (
      {/* 此时Provider没有传入value属性,默认会将value设置为undefined */}
      <UserContext.Provider>
        <UseUserInfoComponent />
      </UserContext.Provider>
    )
  }
}

class UseUserInfoComponent extends Component {
  render() {
    return (
      <UserContext.Consumer>
        {
          // 这里是context的值为undefined,因为Provider没有传value
          context => (
            <div>
              <p>{context.name}</p> {/* 报错 */}
            </div>
          )
        }
      </UserContext.Consumer>
    )
  }
}
复制代码

正确的使用createContext传入的默认值的用法是不提供Provider

const UserContext = createContext({
  user: {
    name: 'max',
  },
})
class App extends Component {
  render() {
    return (
      <UseUserInfoComponent />
    )
  }
}
class UseUserInfoComponent extends Component {
  render() {
    return (
      <UserContext.Consumer>
        {
          context => (
            <div>
              <p>{context.name}</p> {/* 可以获取到默认值 */}
            </div>
          )
        }
      </UserContext.Consumer>
    )
  }
}
复制代码
  • 任何订阅者(Consumer)都可以直接修改context,这会导致后续的订阅者获取到修改后的context值,但这显然是不可取的。如果需要修改,应该统一由发布者(Provider)修改。


未完待续。。。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值