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

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

Barbara Streisand
Barbara Streisand原創
2024-12-26 09:11:10697瀏覽

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中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn