[ffxixslh] React Docs [beta] - 学习笔记(3)

Context

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

Context: an alternative to passing props

步骤:

  1. Create a context.

  2. Use that context from the component that needs the data.

  3. Provide that context from the component that specifies the data.

例如:

import React, {useContext} from 'react';

const themes = {
    light: {
        foreground: '#000000',
        background: '#eeeeee',
    },
    dark: {
        foreground: '#ffffff',
        background: '#222222',
    }
};

// 1. 创建上下文 context ,设置默认值 themes.light
const ThemeContext = React.createContext(themes.light);

function App() {
    return (
        // 3. 使用 context 对象的 Provider 向子组件提供 value
        <ThemeContext.Provider value={themes.dark}>
            <Toolbar />
        </ThemeContext.Provider>
    );
}

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

// 2.1 使用 useContext 
function ThemeButton() {
    // useContext 直接获取 context
    const theme = useContext(ThemeContext); // (*)
    return (
        <button 
            style={{ 
                background: theme.background,
                color: theme.foreground 
            }}
        >
            I am styled by theme context!
        </button>
    );
}

// 2.2 使用 Consumer
function ThemeButton() {
    return (
        // 3. 使用 Consumer 接收 Provider 提供的 value (theme, 命名随意)
        <ThemeContext.Consumer>
            {theme => (      // (*)
                <button
                    style={{
                        background: theme.background,
                        color: theme.foreground 
                    }}
                >
                    I am styled by theme context!
                </button>
            )}
        </ThemeContext.Consumer>
    );
}

Using and providing context from the same component

你可以手动为每个层级都赋予对应的 level ,也可以用递归的思想处理 Provider 提供的 value:

import { useContext } from 'react';
import { LevelContext } from './LevelContext.js';

export default function Section({ children }) {
  const level = useContext(LevelContext);        // (*)
  return (
    <section className="section">      
      <LevelContext.Provider value={level + 1}>  
        {children}
      </LevelContext.Provider>
    </section>
  );
}

因为每个 section 都可以从它的上级 section 获取 level, 所以传递 level + 1 可以自动获取对应层级的 level 值,这样就可以不用为每个 Heading 或 Section 手动传入 level 值。

Before you use context

Context 非常具有诱惑力! 然而,这同样意味着非常容易过度使用。仅仅因为你需要传入一些 props 到几个层级中,并不意味着你需要将这些信息放到 context 中。

你应该在使用 context 之前考虑这些建议 :

  1. Start by passing props. If your components are not trivial, it’s not unusual to pass a dozen props down through a dozen components. It may feel like a slog, but it makes it very clear which components use which data! The person maintaining your code will be glad you’ve made the data flow explicit with props.
  2. Extract components and pass JSX as children to them. If you pass some data through many layers of intermediate components that don’t use that data (and only pass it further down), this often means that you forgot to extract some components along the way. For example, maybe you pass data props like posts to visual components that don’t use them directly, like <Layout posts={posts} />. Instead, make Layout take children as a prop, and render <Layout><Posts posts={posts} /></Layout>. This reduces the number of layers between the component specifying the data and the one that needs it.

这有一篇文章介绍了使用组件组合来优化状态传递:使用组件组合优化状态传递 Component Composition

如果这些方法都不适合,请考虑使用 context。

Use cases for context

  • Theming: 如果你的 App 允许用户更改它的外观 (e.g. dark mode), 你可以在 app 的顶层提供 Provider ,然后在需要调整其视觉外观的组件中使用它
  • Current account: 许多组件可能需要知道当前登录的用户。将它放进 context 中可以在树中的任何地方使其更加便利地读取。一些应用程序还允许你同时操作多个帐户 (e.g. to leave a comment as a different user). In those cases, it can be convenient to wrap a part of the UI into a nested provider with a different current account value.
  • Routing: Most routing solutions use context internally to hold the current route. This is how every link “knows” whether it’s active or not. If you build your own router, you might want to do it too.
  • Managing state: As your app grows, you might end up with a lot of state closer to the top of your app. Many distant components below may want to change it. It is common to use a reducer together with context to manage complex state and pass it down to distant components without too much hassle.

Context is not limited to static values. If you pass a different value on the next render, React will update all the components reading it below! This is why context is often used in combination with state.

In general, if some information is needed by distant components in different parts of the tree, it’s a good indication that context will help you.

Recap:

  • 如果 createContext 中有传 defaultValue,那么在子组件无法匹配到 Provider 提供的值时,会使用传入的 defaultValue,在外层不包裹子组件时也会使用 defaultValue;

  • 如果 value 为 undefined,不会触发 defaultValue;

  • 如果外部有文件需要用到 context ,那么在调用 createContext 后需要 export 导出该 context;

  • 如果有多个 Provider,对需要接收 value 的子组件进行逐层嵌套即可。实际开发中会使用 Redux 代替;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值