react 中 context 的理解

1、为什么要使用 context

没有 context 这个概念之前,我们在组件中自上而下传递数据是通过 props 属性来实现的;如果层级不多用 props 还好,但是如果层级多了,并且只是最后一层会用到,那我们是不是每一层都得写一个 props,这样的话代码写起来很繁琐,不够优雅,不容易维护;所以 context 的出现可以解决这个问题。context 提供了一个无需为每层组件手动添加 props,就能在组件之间进行数据传递的方法。

2、怎么使用 context

React.createContext:创建一个装上下文的容器组件,defaultValue 可以设置需要共享的默认数据;只有在没有被 Provider 容器包裹下的组建使用 context,默认值才会生效;
Context.Provider:提供者,用于提供共享数据的地方,value 属性设置什么数据就共享什么数据;
Context.Consumer:消费者,专门消费 Provider 提供的共享数据,Consumer 需要嵌套在 Provider 下面,才能通过回调的方式拿到共享的数据;(只有函数组件会用到)
Class.contextType:记住是用于指定 contextType 等于当前的 context,必须指定,才能通过 this.context 来访问到共享的数据;(只有类组件会用到)
Context.displayName:context 对象接收一个名为 displayName 的属性,类型为字符串。React DevTools 使用该字符串来确定 context 要显示的内容。

3、使用案例

// theme-context.js
import React from 'react';
export const themes = {
    light: {
        foreground: '#000',
        background: '#eee'
    },
    dark: {
        foreground: '#fff',
        background: '#222'
    }
}

// Step1: 创建一个装上下文的容器
export const ThemeContext = React.createContext(
    themes.dark // defaultValue 默认值
)
// App.js
import React, { Component } from 'react'
import { themes, ThemeContext } from './theme-context.js'
import ToolBar from './component/Toolbar'

export default class App extends Component {
    constructor(props) {
        super(props)
        this.state = {
            theme: themes.dark
        }
    }
    
    toggleTheme = () => {
        this.setState(state => ({
            theme: state.theme === themes.dark ? themes.light : themes.dark
        }))
    }

    render () {
        return (
            {/* Step2: 在顶层组件设置需要共享的数据, 到时候在ToolBar里面会用到 */}
            <ThemeContext.Provider value={this.state.theme}> 
                <ToolBar changeTheme={this.toggleTheme}/>
            </ThemeContext.Provider>
        )
    }
}
// ToolBar.js
import React, { Component } from 'react'
import { ThemeContext } from './theme-context.js'

// 1. 如果子组件是类组件,需要指定contextType等于当前的context(也是两种方式)
export default class ToolBar extends Component {
    // 方式1:在class组件中声明静态属性static
    // static contextType = ThemeContext 
    render () {
        let theme = this.context
        return (
            <div style={{ border: '1px solid #000', background: theme.background }}>
                <h2 style={{ color: theme.foreground }}>ToolBar</h2>
                <button onClick={this.props.changeTheme}>
                    Change Theme
                </button>
            </div>
        )
    }
}
// 方式2: 在class组件外面指定
ToolBar.contextType = ThemeContext

// 2. 如果子组件是函数式组件,需要用Consumer组件来包裹,通过value拿到数据
export default function ToolBar (props) {
    return (
        <ThemeContext.Consumer>
            { theme => (
                <div style={{ border: '1px solid #000', background: theme.background }}>
                    <h2 style={{ color: theme.foreground }}>ToolBar</h2>
                    <button onClick={props.changeTheme}>
                        Change Theme
                    </button>
                </div>
            )}
        </ThemeContext.Consumer>
    )
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值