5分钟了解React Context API

348 阅读3分钟

本文为翻译文章,原文再次React Context in 5 Minutes

React Context API已经成为了很多状态管理工具的选择,通常情况下可以完全取代Redux,在这个5分钟了解React Context教程当中,你将会了解到Context是什么并且如何使用它!

首先,看一下下面这棵树,树的底部是一个个的组件

你可以很轻松的在底部组件里面增加state,但到目前为止,将数据传递给同级组件的唯一方法就是将state传递到更高的组件当中,然后又通过props将其传递给同级组件。

但是如果稍后我们发现使用state的组件的同级也需要数据,则必须再次传递state,并通过props将其传回。

虽然这样可以解决问题,但是如果在不同分支上的组件都需要问题,则会出现很多问题。

在这个案例当中,我们需要将state从顶层的应用通过各个中间组件传递到最底层的组件,即使中间的那些组件不需要这个state。这一繁琐而耗时的过程被称为prop drilling。

这就是 Context 这个 API 需要存在的场景。它提供了一种不再需要层层传递props就可以将数据传递到最底层的方法。你可以把它想象成一个数据捕捉的组件-甚至中间的那些组件根本不知道发生了什么。

为了演示这一点,我们创建了这个美观(而且非常有用)的昼夜切换图像。

如果你想看完整的代码,请务必查看这篇文章

创建上下文

首先,我们创建一个新的Context,由于我们希望整个应用程序能够访问该应用,所以我们将index.js并将应用程序包装在ThemeContext.Provider中。

import React from 'react';
import ReactDOM from 'react-dom';
import ThemeContext from './themeContext';

import App from './App';

ReactDOM.render(
    <ThemeContext.Provider value={"Day"}>
        <App />
    </ThemeContext.Provider>,
    document.getElementById('root')
)

在App.js,我们返回一个简单的组件

import React from 'react';
import Image from './Image';

class App extends React.Component {
    render() {
        return (
            <div className="app">
                <Image />
            </div>
        )
    }
}

export default App;

我们的目标是在Image.js中使用Context将className从Day切换到Night,这取决于我们想要渲染哪个图片。为了做到这一点,我们将一个静态属性添加到我们的组件ContextType,并且使用字符串插入到Image组件里面的className当中

import React from 'react';
import Button from './Button';
import ThemeContext from './themeContext';

class Image extends React.Component {
    render() {
        const theme = this.context;
        return (
            <div className={`${theme}-image image`}>
                <div className={`${theme}-ball ball`} />
                <Button />
            </div>
        )
    }
}

Context.Consumer

不幸的是,此方法仅适用于基于类的组件。如果你已经学习了Hooks in React,你会知道我们现在可以用function组件做任何事情。所以为了更好的衡量,我们应该将组件转换为function组件,同时使用ThemeContext.Consumer通过app传递信息。

这是通过将我们的元素封装在<ThemeContext.Consumer>的实例中来完成的,并且在该实例中(子元素所在的位置)提供了一个返回元素的函数。这使用了 render prop 模式,在这种模式中,我们作为子函数提供一个常规函数,返回一些JSX来呈现。

import React from 'react';
import Button from './Button';
import ThemeContext from './themeContext';

function Image(props) {
    // 我们不再需要
    // const theme = this.context;
    
    return (
        <ThemeContext.Consumer>
            {theme => (
                <div className={`${theme}-image image`}>
                    <div className={`${theme}-ball ball`} />
                    <Button />
                </div>
            )}
        </ThemeContext.Consumer>
    )
}

export default Image;

注意: 我们也需要将Button组件包裹在<ThemeContext.Consumer>,这允许我们稍后向按钮添加功能。

import React from "react";
import ThemeContext from "./themeContext";

function Button(props) {
  return (
    <ThemeContext.Consumer>
      {context => (
        <button className="button">
          Switch
          <span role="img" aria-label="sun">
            🌞
          </span>
          <span role="img" aria-label="moon">
            🌚
          </span>
        </button>
      )}
    </ThemeContext.Consumer>
  );
}

export default Button;

Extract Context Provider

我们目前正在通过Provider传递一个硬编码的值