React中的Context理解

今天看了下react官网的context,记录下学习过程和自己对context的理解。下面从为什么要用怎么用两个方面来解释,并参照官网,列出简单的例子来加深记忆。

单词:

provider: /prəˈvaɪdə(r)/ 提供者

consumer:/kənˈsjuːmə(r)/ 消费者

为什么要用Context?:

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

怎么使用?:

要想知道怎么使用,先把ContextApi过一遍。这里简单总结下各个Api的用法,更详细的还是参照官网

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

接下来是怎么使用,总的来说就是顶层组件提供数据,下面消费组件来消费/读取数据。通过demo一步步来解释:

此demo是通过工具栏中的按钮来切换主题色

  1. 首先,创建一个theme-context.js文件,用于创建一个装上下文的容器
// 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 默认值
)
  1. 在顶层组件设置需要共享的数据
// 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 (
            <div>
                <ThemeContext.Provider value={this.state.theme}> {/* Step2: 在顶层组件设置需要共享的数据, 到时候在ToolBar里面会用到*/}
                    <ToolBar changeTheme={this.toggleTheme}/>
                </ThemeContext.Provider>
            </div>
        )
    }
}
  1. 子组件使用(消费)context(类组件和函数式组件对应两种方式)
// ToolBar.js
import React, { Component } from 'react';
import { ThemeContext } from './theme-context.js'

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

// ThemeButton.js中要使用共享数据也是同理,这里贴出ThemeButton.js的代码
// ThemeButton.js
import React, { Component } from 'react';
import { ThemeContext } from './theme-context.js';

export default function ThemeButton(props) {
    return (
        <ThemeContext.Consumer>
            {theme => (
                <button 
                    {...props}
                    style={{background: theme.background, color: theme.foreground}}
                    ></button>
            )}
        </ThemeContext.Consumer>
    )
}

查看完整代码

注:要看懂context的代码也是按照这些步骤来看会简单得多。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。