初探React Context API

特别声明:如果您喜欢小站的内容,可以点击年卡¥199.00元(原价: ¥598元)季卡¥78.00元(原价: ¥168元)月卡¥28.00元(原价: ¥68元)进行全站阅读。如果您对付费阅读有任何建议或想法,欢迎发送邮件至: airenliao@gmail.com!或添加QQ:874472854(^_^)

最近在整理CSS自定义属性在React中的使用时了解到“可以使用React Context API相关的知识更好的在React组件中使用CSS自定义属性”,但是自己对这方面的知识了解的并不多,因此想借此机会来学习React Context API相关的知识。也基于这个原因有了这篇文章。

为什么要React Context API

我们从一个React的实例开始。假设你要构建一个React的应用,该应用有一个最简单的功能,就是Dark Mode的切换。简单地说,在Web应用上一个切换组件(比如ThemeToggle),用户点击该切换按钮可以让页面在暗色系(dark)和亮色系(light)之间切换。

通常我们会通过props为所有组件提供当前主题的模式,并使用state来更新当前的主题。

/src/components/目录下分别创建了GrandChildChildParentComponentThemeToggle几个组件:

示例代码如下:

// /src/components/GrandChild
import React from 'react'

const GrandChild = (props) => {
    const styled = {
        color: `${props.theme.color}`,
        background: `${props.theme.background}`
    }
    return <h1 style={{...styled,...props.styles}}>Theme Toggle</h1>
}

export default GrandChild;

// /src/components/Child
import React from 'react'
import GrandChild from '../GrandChild'

const Child = (props) => {
    const styled = {
        border: `5px solid ${props.theme.color}`,
        padding: `10vmin 20vmin`,
        borderRadius: '8px'
    }

    return <GrandChild theme = {props.theme} styles={styled} />
}

export default Child

// /src/components/ParentComponent
import React from 'react'
import Child from '../Child'

const ParentComponent = (props) => <Child theme = {props.theme} />

export default ParentComponent

// /src/components/ThemeToggle
import React from 'react'

const ThemeToggle = (props) => {
    const styled = {
        background: `${props.theme.background}`,
        color: `${props.theme.color}`,
        border: `4px solid currentColor`,
        borderRadius: `6px`,
        padding: `2vmin 4vmin`,
        margin: `4vmin`,
        cursor: `pointer`
    }
    return <button onClick={props.click} style={styled}>Toggle Dark Mode</button>
}

export default ThemeToggle

// /src/App.js
import React, {Fragment} from 'react';
import ParentComponent from './components/ParentComponent'
import ThemeToggle from './components/ThemeToggle'

const dark = {
    background: '#121212',
    color: '#fff'
}

const light = {
    background: '#fff',
    color: '#444'
}

const App = () => {
    const [theme, setTheme] = React.useState('light')

    const onClickHander = () => {
        theme === 'light' ? setTheme('dark') : setTheme('light')
    }


    return <Fragment>
        <ParentComponent theme={theme === 'light' ? light : dark} />
        <ThemeToggle click={onClickHander} theme={theme === 'light' ? light : dark} />
    </Fragment>
}

export default App;

效果如下:

在这个示例中,在ParentComponent组件中指定了theme这个props,并且将这个props一级一级往下传,传给组件树下的所有组件。即,将theme传递到需要它的地方,在本例中会传到GrandChild组件。而Child组件和themeprops)没有任何关系,它只是作为一个媒体而以。

试想一下,在React中组件树就有点类似于我们熟悉的DOM树:

注意,上图中每个白色的矩形方框代表的就是React的组件

正如上图所示,我们可以在最底层组件中添加state,但如果要将数据传递给兄弟组件的话,在React Context API之前,我们只能将state放到他们的父组件中(组件树中更高的组件位置),然后通过props将其传递回同级组件:

就像上面的示例,我们需要将state从组件树的最顶层一级一级往下传,哪怕是所有中间层组件不需要使用这些数据,但它必须为了后面的组件做为媒介,将state传递到最底层组件。

在React社区中,将这种冗长和耗时的过程称为Prop Drilling

对应到上面的示例中,那就是:

React Context API正是用来解决Prop Drilling的问题。React Context API提供了一种通过ProviderConsumer用来提供数据和消费数据,它们可以在组件件中传递数据,最主要的是不必要一级一级的通过props向组件树传递state。简单地说,在组件树最顶层的组件中通过Provider提供数据,在后面的任何一个子组件树可以通过Consumer来消费Provider提供的数据:

React Context API简介

React的官网是这样描述Context的:

Context提供了一个无需为每层组件手动添加props,就能在组件树间进行数据传递的方法

在这个特性还没出现之前,在React应用中数据的通讯是通过props属性自上而下(由父及子)进行传递的,换句话说,必须通过props传递到每个组件中,然后在组件中重复相同的过程。但这种做法对于某些类型的属性而言是极其繁锁的,也会变得非常的糟糕,最终可能会导致props在我们的组件中要不断的一层一层嵌套。

React Context API的出现主要是为了帮助我们解决这方面的问题,它提供了一种在组件之间共享此类值的方式,而不必显式地通过组件树的逐层传递props。也就是说,它允许父组件隐式地将数据传递给子组件(不管组件树有多深)。换句话说,可以将数据添加到父组件中,然后任何子组件都可以访问它

假设我们有这样的一个使用场景,在一个React应用中,我们有AppContainerFormButton四个组件,它们之间是依次被嵌套:

App ➜ Container ➜ Form ➜ Buttton

假如我们使用props传递就需要一层一层往里传:

换成Context,就可以直接获取最顶层App组件绑定的值:

React Context API入门级应用

对于像我这样的初级使用者而言,要想彻底的了解React Context API,只能从最简单的应用开始。为了更好的理解它的使用,我们从最简单的示例开始。

创建上下文对象

在JavaScript中(或React)中常将Context称为上下文

在React中使用Context的话,我们首要做的就是创建上下文对象(Context Object)。可以使用React上的.createContext()创建一个Context对象:

const DataContext = React.createContext()

尝试着把这个Context对象DataContext在控制台上打印出来:

这个时候可以从组件树中离自身最近的那个匹配的Prrovider中读取到当前的context值。

只有当组件所处的树中没有匹配到Provider时,其defaultValue参数才会生效。这有助于在不使用Provider包装组件的情况下对组件进地测试。

另外,createContext()方法提供了ProviderConsumer能力,其中一个是提供者,另一个是消费者,而且这两个属性都是成对出现的,即每一个Provider都会有对应的一个Consumer

Provider将作为父组件使用,它持有所有Consumer都可以共享的值。注意,Consumer只能用于Provider的子组件

使用Provider提供数据

上一步,使用React.createContext()创建了一个名为DataContext的上下文对象,在其中,我们用一些值(value)初始化一个状态(state),可以使用DataContextProvider接受一个value属性,传递给子组件消费(Consumer

const App = () => <DataContext.Provider value={{userName: 'Airen', age: 30 }}>
    <h4>Child Component</h4>
</DataContext.Provider>;

Providervalue属性的值可以是字符串、数字或对象。

消费Provider提供的数据

Provider创建了数据,其创建的数据可以通过context对象的Consumer属性给子组件消费。主要有三种方法来消费Provider属性创建的数据。

使用Consumer组件消费数据

创建一个新组件,并且在该组件中使用DataContextConsumer来消费数据。这将返回一个函数,该函数允许组件消费Provider中设置的值。比如:

const ParagraphChildComponent = () => <DataContext.Consumer>
    { value => <h4>I'm {value.userName}, {value.age} 
剩余80%内容付费后可查看

如需转载,烦请注明出处:https://www.w3cplus.com/react/react-context-api.html

如果文章中有不对之处,烦请各位大神拍正。如果你觉得这篇文章对你有所帮助,打个赏,让我有更大的动力去创作。(^_^)。看完了?还不过瘾?点击向作者提问!

赏杯咖啡,鼓励他创作更多优质内容!
返回顶部