React Context 的范围是什么?

IT技术 reactjs
2021-05-16 19:01:21

我不清楚Context可以在 React 应用程序中的何处创建。我可以在组件树的任何位置创建上下文吗,如果是这样,该上下文是否仅适用于它创建位置的子级?或者 Context 本质上是全球性的?

我可以在文档的哪里找到这个?

案例:我在页面上多次重用一个组件,并希望使用上下文来处理子组件的数据,但该上下文需要对每个子树都是唯一的。

3个回答

有两个独立的东西:上下文对象和上下文提供者。

上下文对象在全局创建一次(具有可选的默认值,如果没有从组件父级传递提供程序,则该值是全局的):

const FontContext = createContext('Courier');

虽然上下文提供者实际上传递了自己对上下文的本地覆盖,但这仅适用于其子级:

<FontContext.Provider value='Consolas'>
  {children}
</FontContext.Provider>

有趣的部分是上下文级联:

<>
  <MyFontConsumer /> // value is 'Courier', the default
  <FontContext.Provider value='Consolas'>
    <MyFontConsumer /> // value is 'Consolas'
    <FontContext.Provider value='TimesRoman'>
      <MyFontConsumer /> // value is 'TimesRoman'
    </FontContext.Provider>
    <MyFontConsumer /> // value is 'Consolas'
  </FontContext.Provider>
</>

要使用组件中的上下文,您可以使用useContext()钩子(您可以使用特殊<FontContext.Consumer>组件或MyClassComponent.contextType代替)它要求您传递相同的对象。

避免传递上下文对象的首选方法是将它们全部保存在同一个组件中并导出自定义钩子:


const FontContext = createContext('Courier')

export function FontProvider({value, children}) {
  return <FontContext.Provider value={value}>
    {children}
  </FontContext.Provider>
}

export function useFont() {
  return useContext(FontContext)
}

现在你可以在你的组件中使用它:

import {FontProvider, useFont} from './FontProvider'

function App() {
  const font = useFont() // value is 'Courier', the default

   return <FontProvider value='TimesRoman'>
      <MyChild />
   </FontProvider>
}

function MyChild() {
  const font = useFont() // value is 'TimesRoman'
  ...
}

我不清楚Context可以在 React 应用程序中的何处创建。我可以在组件树的任何位置创建上下文吗?

从技术上讲,上下文对象可以在任何地方使用 来创建createContext,但要实际将该值设置为默认值以外的值,您需要一个提供程序组件。上下文将通过其使用者或useContext提供者的任何子组件中的钩子可用

该上下文是否仅适用于其创建位置的子级?

如果“创建”是指提供者所在的位置,是的。但是,使用新的上下文 API,即使没有提供程序,您也可以设置默认值。

或者 Context 本质上是全球性的?

不,并非本质上,尽管上下文通常放置在应用程序的根组件之内或之上,以便出于所有实际目的变得全局。

我可以在文档的哪里找到这个?

案例:我在页面上多次重用一个组件,并希望使用上下文来处理子组件的数据,但该上下文需要对每个子树都是唯一的。

据我了解,您在这里有两种选择:

  1. 使用具有不同提供者的单个上下文在子树中覆盖它
  2. 每个子树都有不同的上下文

这是一个很好的问题。我想特别分享一些关于上下文范围的内容。

语境

上下文实际上是一个“全局”的想法,因为在你创建它的时候,它没有附加到任何纤维/组件。

  const UserContext = React.createContext()
  export default UserContext

这就是为什么它通常会立即导出。为什么?由于所有提供者和消费者在正常情况下都需要在不同的文件中访问它。尽管您可以将它们放在同一个文件中,但这并没有表现出上下文的性质。它被用来保存一个为整个应用程序持久化的“全局”值。底层value只是存储一个临时的作为下面描述的范围输入参数。真正的value隐藏在幕后,因为它根据范围不断变化。

范围

上下文可能在钩子之前很久就被创建了。React 没有其他方法可以将数据发送到更深的特定距离而不显示在props中。上下文的设计类似于函数,在内部 React 使用堆栈在进入或离开提供者时弹出/推送上下文。因此,当相同的上下文提供程序如下嵌套时,您将看到类似的行为。

const Branch = ({ theme1, theme2 }) => {
  return (
    <ThemeContext.Provider value={theme1}>
      // A. value = theme1
      <ThemeContext.Provider value={theme2}>
        // B. value = theme2
      </ThemeContext.Provider>
      // C. value = theme1
    </ThemeContext.Provider>
  )
}

如果你对待每一个ThemeContext与输入参数的函数value,那么它的清楚什么是位置的值ABC在某种程度上,上下文与函数没有什么不同:) 这也是一个很好的例子,向你展示 propvalue与上下文ThemeContext跟踪的值不同,否则你最终会得到一个固定值,要么theme1theme2在幕后,有一个全局机制:)

笔记:

Context 被设计为非常强大,但是由于过度渲染问题,它从未达到那个水平。但是我想 React 中没有其他替代品来共享变量,因此它有再次流行的趋势,尤其是在引入了useContextSelectorunder proposal的情况下。我在这里的博客中对上面做了一些解释,https://windmaomao.medium.com/react-context-is-a-global-variable-b4b049812028