一、props 传递数据的烦恼

作为子组件的 Toolbar 必须显式定义 theme 属性, ThemedButton 才能够获的 theme 数据。当 ThemedButtonApp 之间嵌套了很多层,且使用ThemedButton 的页面又非常多,那么工作就会变的异常麻烦。

class App extends React.Component {
    render() {
        return <Toolbar theme="dark" />;
    }
}

function Toolbar(props) {
    return (
        <div>
            <ThemedButton theme={props.theme} />
        </div>
    );
}

class ThemedButton extends React.Component {
    render() {
        return <Button theme={this.props.theme} />;
    }
}

二、Context 解决方案

用 React.createContext 创建的 Context 对象,不论组件嵌套多深,都无需再中间组件显式传递 theme 属性,也可以把 theme 属性值传递下去。

const ThemeContext = React.createContext('light');
class App extends React.Component {
    render() {
        return (
            <ThemeContext.Provider value="dark">
                <Toolbar />
            </ThemeContext.Provider>
        );
    }
}

function Toolbar() {
    return (
        <div>
            <ThemedButton />
        </div>
    );
}

class ThemedButton extends React.Component {
    static contextType = ThemeContext;
    render() {
        return <Button theme={this.context} />;
    }
}

三、重要概念说明
1、React.createContext
// 创建Context对象,并设置缺省值(defaultValue)。
const MyContext = React.createContext(defaultValue);

2、Context.Provider
// 给 Context 对象赋值
<MyContext.Provider value={/* 某个值 */}></MyContext.Provider>

3、Class.contextType

class 组件中获取Context对象的数据,分两步:

  • 把 class组件的 contextType 属性 与 Context对象关联起来;
  • 通过 this.context 来获取数据。
  • 备注:获取数据的过程就是:从父组件一直往上找最近 Context.Provider 的 value 值,找不到就使用 Context 的缺省值。

    // 使用方法一
    class MyClass extends React.Component {
        render() {
            let value = this.context;
        }
    }
    MyClass.contextType = MyContext;
    
    // 使用方式二
    class MyClass extends React.Component {
        static contextType = MyContext;
        render() {
            let value = this.context;
        }
    }

4、Context.Consumer
// 让组件中Context数据,随着Context的变化而自动变化
<MyContext.Consumer>
    {value => (<div style={{ backgroundColor: value.background }}></div>)}
</MyContext.Consumer>

5、Context.displayName
// 类型为字符串,是Context在React DevTools显示的名字,方便调试。

const MyContext = React.createContext(/* some value */);
MyContext.displayName = 'MyDisplayName';

<MyContext.Provider> // "MyDisplayName.Provider" 在 DevTools 中
<MyContext.Consumer> // "MyDisplayName.Consumer" 在 DevTools 中

四、函数组件,使用Context

函数组件中没有 contextType 属性,所以使用 useContext 这个 Hook 函数来解决 props 传递数据的烦恼。

const themes = {
    light: {
        foreground: "#000000",
        background: "#eeeeee"
    },
    dark: {
        foreground: "#ffffff",
        background: "#222222"
    }
};
// 第一步:创建Context,并设置缺省值
const ThemeContext = React.createContext(themes.light);

function App() {
    // 第二步:给Context赋值
    return (
        <ThemeContext.Provider value={themes.dark}>
            <Toolbar />
        </ThemeContext.Provider>
    );
}

function Toolbar(props) {
    return (
        <div>
            <ThemedButton />
        </div>
    );
}

function ThemedButton() {
    // 第三步:将Context与函数组件,通过useContext关联
    const theme = useContext(ThemeContext);

    // 第四步:直接使用
    return (
        <button style={{ background: theme.background, color: theme.foreground }}>
            I am styled by theme context!
        </button>
    );
}

五、参考链接:

Learn_anything
7 声望0 粉丝

收集互联网优质资源!