首页 > web前端 > js教程 > 用例子解释 React 中的作用域上下文

用例子解释 React 中的作用域上下文

Barbara Streisand
发布: 2024-12-26 09:11:10
原创
702 人浏览过

Explaining Scoped Context in React with example

React Context 是一个全局变量

在 Javascript 中,变量的作用域位于函数定义内。

用示例解释 React 中的作用域上下文

React Context 通常被描述为一种管理全局状态的机制,充当可跨 React 组件树访问的共享变量。虽然这个描述是准确的,但它过于简化了 Context 的功能。在本文中,我们将深入探讨如何有效地确定 Context 的范围,确保仅在需要的地方使用它并避免不必要的重新渲染。

什么是 React 上下文?

React Context 提供了一种通过组件树传递数据的方法,而无需在每个级别手动传递 props。它是使用 React.createContext 创建的,由 Provider 和 Consumer 对组成。 Provider 组件提供值,任何用 Consumer 或 useContext 钩子包装的组件都可以访问它。

这是一个基本示例:

import React, { createContext, useContext } from "react";

const ThemeContext = createContext("light");

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

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

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return <button>{`Theme: ${theme}`}</button>;
}

export default App;
登录后复制
登录后复制

在此示例中,ThemedButton 可以访问 ThemeContext.Provider 提供的主题值,而无需通过 Toolbar 显式传递 props。

为什么是范围上下文?

虽然 Context 很强大,但不加区别地使用它可能会导致性能问题。当 Context.Provider 提供的值发生更改时,使用该上下文的所有组件都将重新呈现。在复杂的应用程序中,这可能会导致不相关组件不必要的重新渲染。

Scoped Context 是指将 Context 的使用限制在组件树中真正需要它的部分的做法。这种方法有助于保持性能并保持组件结构干净且易于理解。

复合组件面临的挑战

考虑涉及复合组件的场景,例如 Radix Primitives 等库提供的组件。这些组件通常在内部使用 Context 来管理状态和交互。然而,当相似的组件组合在一起时,可能会出现问题,导致上下文冲突。

基数基元示例

Radix Primitives 提供了高度可组合的 API,用于构建可访问的组件。这是一个例子:

<AlertDialog.Root>
  <Dialog.Root>
    <Dialog.Trigger />
    <Dialog.Content>
      <AlertDialog.Trigger /> {/* note the alert trigger in dialog content */}
    </Dialog.Content>
  </Dialog.Root>

  <AlertDialog.Content />
</AlertDialog.Root>
登录后复制
登录后复制

这里出现了一个问题,因为 AlertDialog 是 Dialog 的组合,具有满足 AlertDialog 要求的附加功能。这意味着AlertDialog.Root也是一个Dialog.Root,因此它同时提供了DialogContext和AlertDialogContext。

在此设置中,AlertDialog.Trigger(也是 Dialog.Trigger)可能会通过 useContext(DialogContext) 检索错误的上下文,最终得到来自 Dialog.Root 而不是 AlertDialog.Root 的上下文。因此,单击 AlertDialog.Trigger 可能会切换 Dialog.Content,而不是按预期运行。

范围上下文解决方案

为了防止此类问题,Radix Primitives 使用作用域上下文。作用域上下文确保 AlertDialog.Trigger 仅与 AlertDialog 部件交互,并且不会意外地从类似组成的组件中检索上下文。这是通过在内部创建一个新上下文并通过自定义属性(例如 __scopeDialog)将其传递给 Dialog 组件来实现的。然后,Dialog 组件在其 useContext 调用中使用此作用域上下文,以确保隔离。

来自 radix ui github 存储库的源代码:

https://github.com/radix-ui/primitives/blob/dae8ef4920b45f736e2574abf23676efab103645/packages/react/dialog/src/Dialog.tsx#L69

以下是作用域上下文在 Radix UI 中如何工作的抽象:

  1. 范围创建:createScope 实用程序为每个组件或复合组件生成唯一的命名空间。这确保了每组上下文都是隔离的并且不会与其他上下文发生冲突。

    import React, { createContext, useContext } from "react";
    
    const ThemeContext = createContext("light");
    
    function App() {
      return (
        <ThemeContext.Provider value="dark">
          <Toolbar />
        </ThemeContext.Provider>
      );
    }
    
    function Toolbar() {
      return <ThemedButton />;
    }
    
    function ThemedButton() {
      const theme = useContext(ThemeContext);
      return <button>{`Theme: ${theme}`}</button>;
    }
    
    export default App;
    
    登录后复制
    登录后复制
  2. 作用域提供者:创建上下文时,它们与作用域绑定。这将提供者和消费者绑定到同一个命名空间。

    <AlertDialog.Root>
      <Dialog.Root>
        <Dialog.Trigger />
        <Dialog.Content>
          <AlertDialog.Trigger /> {/* note the alert trigger in dialog content */}
        </Dialog.Content>
      </Dialog.Root>
    
      <AlertDialog.Content />
    </AlertDialog.Root>
    
    登录后复制
    登录后复制
  3. 消费者隔离:作用域挂钩,如 useDialogScope,确保消费者仅访问其预期范围内的上下文。

    import { createScope } from '@radix-ui/react-context';
    
    const [createDialogContext, useDialogScope] = createScope('Dialog');
    
    登录后复制

范围上下文的好处

  • 上下文冲突预防:通过确定上下文范围,AlertDialog.Trigger 等组件始终可以找到其关联的上下文 (AlertDialogContext),即使嵌套在其他上下文中也是如此。

  • 灵活组合:作用域上下文支持灵活安全的组件组合,确保交互保持可预测。

  • 可重用性:开发人员可以在不同范围内重用通用组件(例如 Dialog.Trigger),无需修改。

它如何应用于示例

在您的示例中:

  • AlertDialog.Root 创建一个有作用域的 AlertDialogContext,封装其状态和交互。

  • 嵌套的 Dialog.Root 和 AlertDialog.Trigger 共存而不会发生冲突,因为它们各自引用其各自的作用域上下文。

  • 此设计模式是 Radix UI 的一个关键功能,可确保复杂的组件层次结构无缝工作,而不会出现意外行为。

参考:

  1. https://dev.to/romaintrotard/use-context-selector-demystified-4f8e

  2. https://github.com/radix-ui/primitives

  3. https://react.dev/reference/react/createContext

以上是用例子解释 React 中的作用域上下文的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板