Context

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

为什么需要 Context?

在一个典型的 React 应用中,数据是通过 props 属性自上而下(由父及子)进行传递的,但这对于某些类型的属性而言是极其繁琐的(例如:地区偏好,UI 主题),这些属性是应用程序中许多组件都需要的。Context 提供了一种在组件之间共享此类值的方式,而不必显式地通过组件树逐层传递 props。

注意: 在 ReScript 中, 由于其 JSX prop 双关 功能和强大的类型推导,传递 props 属性要比 TS / JS 中简单得多,所以最好保持简单,只做 props 传递。Less magic means more transparency!

何时使用 Context

Context 的设计目的是为了在整个组件树中共享“全局”数据,例如当前认证的用户、主题或首选语言。举个例子,在下面的代码中,我们通过一个 “theme” 属性手动调整一个按钮组件的样式:

ReScriptJS Output
// src/App.res
type theme = Light | Dark;

module Button = {
  @react.component
  let make = (~theme) => {
    let className = switch theme {
      | Light => "theme-light"
      | Dark => "theme-black"
    };
    <button className> {React.string("Click me")} </button>
  }
}

module ThemedButton = {
  @react.component
  let make = (~theme) => {
    <Button theme />
  }
}

module Toolbar = {
  @react.component
  let make = (~theme) => {
    <div>
      <ThemedButton theme/>
    </div>
  }
}

@react.component
let make = () => {
  // // We define the theme in the
  // // toplevel App component and
  // // pass it down

  // 我们在顶层的 App 组件定义 theme 属性
  // 并将其向下传递
  <Toolbar theme=Dark/>
}

使用 context, 我们可以避免通过中间元素传递 props:

ReScriptJS Output
// src/App.res

module ThemeContext = {
  type theme = Light | Dark;
  let context = React.createContext(Light)

  module Provider = {
    let provider = React.Context.provider(context)

    @react.component
    let make = (~value, ~children) => {
      React.createElement(provider, {"value": value, "children": children})
    }
  }
}

module Button = {
  @react.component
  let make = (~theme) => {
    let className = switch theme {
      | ThemeContext.Light => "theme-light"
      | Dark => "theme-black"
    };
    <button className> {React.string("Click me")} </button>
  }
}

module ThemedButton = {
  @react.component
  let make = () => {
    let theme = React.useContext(ThemeContext.context)

    <Button theme/>
  }
}

module Toolbar = {
  @react.component
  let make = () => {
    <div> <ThemedButton /> </div>
  }
}

@react.component
let make = () => {
  <ThemeContext.Provider value=ThemeContext.Dark>
    <div> <Toolbar /> </div>
  </ThemeContext.Provider>
}