如何设置 React Context

Prop drilling(属性钻取)会毁掉你的代码。你会将数据传递给五层根本不需要它的组件。React Context 可以解决这个问题。然而,大多数设置方式会引入一个新问题。

当你对一个 context hook 使用“转到定义”(Go to Definition)时,你往往会跳转到一个文件中,而那里除了一个微小的 useContext 调用外别无他物。实际的逻辑存在于另一个文件中。你的一整天都在寻找状态逻辑。

你可以通过更好的结构来解决这个问题。

请遵循以下模式:

  • 将 context、公共 hook 和状态逻辑放在同一个文件中。
  • 将 Provider 保持为一个薄壳(thin shell)。
  • 使用 lint 规则来保护你的私有逻辑。

按照如下方式组织你的文件:

src/context/ • GameContext.ts(Context、公共 hook 和状态逻辑) • GameProvider.tsx(一个薄壳)

GameContext.ts 内部,创建三个部分:

  1. context 对象。
  2. 一个供组件使用的公共 hook。如果 context 为 null,该 hook 应该抛出一个错误。这可以确保如果组件位于 provider 之外,它们能够“快速失败”(fail fast)。
  3. 一个用于状态管理的私有 hook。该 hook 包含你的 useStateuseReducer 调用。

通过将公共 hook 和私有逻辑放在同一个文件中,“转到定义”功能将完美运行。你可以直接从组件跳转到逻辑所在处。

但存在一个风险。由于私有 hook 被导出以便 Provider 使用,队友可能会在错误的地方调用它。如果他们这样做,就会创建一个新的、隔离的状态,而不是使用共享的 context。

不要再使用注释来防止这种情况。改用 ESLint 规则。

我创建了 eslint-plugin-restrict-callers 来解决这个问题。你可以定义哪些函数允许调用特定的 hook。

例如,你可以告诉 ESLint 只有 GameProvider 可以调用 useGameStateManagement。如果其他人尝试调用,构建将会失败并显示清晰的错误消息。

工作流总结:

  • 将 context、公共 hook 和私有逻辑组合在一个文件中。
  • 仅使用 Provider 将 hook 的结果传递给 provider value。
  • 如果 context 缺失,在公共 hook 中抛出错误。
  • 使用 ESLint 来强制执行公共 hook 和私有 hook 之间的边界。

来源:https://dev.to/jareddlewis/how-to-set-up-react-context-2c9h