React.createContext的defaultValue点?

mer*_*att 16 javascript reactjs

React 16 Context doc页面上,他们的示例看起来类似于:

const defaultValue = 'light';
const SomeContext = React.createContext(defaultValue);

const startingValue = 'light';
const App = () => (
  <SomeContext.Provider theme={startingValue}>
    Content
  </SomeContext.Provider>
)
Run Code Online (Sandbox Code Playgroud)

似乎defaultValue是无用的,因为如果你改为将startingValue其他东西设置为或者不设置它(它是undefined),它会覆盖它.那很好,它应该这样做.

但那又有什么意义defaultValue呢?

如果我想拥有一个不会改变的静态上下文,那么能够执行下面的操作会很好,并且让提供者通过 defaultValue

const App = () => (
  <SomeContext.Provider>
    Content
  </SomeContext.Provider>
)
Run Code Online (Sandbox Code Playgroud)

Eri*_*rel 48

只是分享我使用 TypeScript 时的典型设置,以完成上面 @tiomno 的回答,因为我认为许多最终到达这里的谷歌用户实际上正在寻找这个:

interface GridItemContextType {
    /** Unique id of the item */
    i: string;
}
const GridItemContext = React.createContext<GridItemContextType | undefined>(
    undefined
);

export const useGridItemContext = () => {
    const gridItemContext = useContext(GridItemContext);
    if (!gridItemContext)
        throw new Error(
            'No GridItemContext.Provider found when calling useGridItemContext.'
        );
    return gridItemContext;
};
Run Code Online (Sandbox Code Playgroud)

在这种情况下,该钩子提供了更安全的输入方式。这undefined defaultValue可以防止您忘记设置提供程序。

  • 我认为这是在 TypeScript 中执行操作的最佳方式,假设没有提供有意义的“defaultValue”。不过,Eric 请注意 - 您不需要在最后使用 `as GridItemContextType` 进行转换,因为 TypeScript 应该已经能够通过上面的条件缩小 `gridItemCheck` 的类型。 (4认同)

Ari*_*yen 16

如果没有Provider,则defaultValue参数用于函数createContext.这有助于隔离测试组件而不包装它们,或者使用Provider中的不同值对其进行测试.

  • 来自https://reactjs.org/docs/context.html#reactcreatecontext:“仅当组件在树中上方没有匹配的Provider时才使用defaultValue参数。这对于隔离测试组件而不进行包装很有帮助注意:将undefined传递为Provider值不会导致使用组件使用defaultValue。” (3认同)
  • 所以这又是一次黑客之上的黑客攻击。 (3认同)
  • 这是Reactjs新文档的答案:https://react.dev/reference/react/createContext#parameters (2认同)

tio*_*mno 6

我的两分钱:

阅读这篇有指导意义的文章后像往常一样Kent C. Dodds的:) 后,我了解到当您解构 useContext 返回的值时, defaultValue 很有用:

在没有 defaultValue 的代码库的一个角落定义上下文:

const CountStateContext = React.createContext() // <-- define the context in one corner of the codebase without defaultValue
Run Code Online (Sandbox Code Playgroud)

并在组件中像这样使用它:

const { count } = React.useContext(CountStateContext)
Run Code Online (Sandbox Code Playgroud)

JS明显会说 TypeError: Cannot read property 'count' of undefined

但是你不能这样做,完全避免使用 defaultValue。

关于考试,我的老师 Kent 说得很好:

React 文档建议提供默认值“有助于在不包装组件的情况下隔离测试组件。” 虽然它确实允许您这样做,但我不同意这比用必要的上下文包装组件更好。请记住,每次您在测试中做了一些您在应用程序中没有做的事情时,都会降低测试可以给您的信心。

额外的打字稿;如果您不想使用 defaultValue,可以通过执行以下操作轻松取悦 lint:

const MyFancyContext = React.createContext<MyFancyType | undefined>(undefined)
Run Code Online (Sandbox Code Playgroud)

您只需要确保稍后添加额外的验证,以确保您已经涵盖了 MyFancyContext === 未定义的情况

  • MyFancyContext ?? '默认'
  • MyFancyContext?.notThatFancyProperty

等等

  • 您链接到的文章说,当您没有将消费者置于适当的提供者中时,将使用“defaultValue”。返回值是否被解构并不重要,这只是一个例子 (2认同)
  • 这次真是万分感谢!不久前,我读到 Dan Abramov 对此的评论(从 d.ts 文件链接的评论:https://github.com/DefinitelyTyped/DefinitelyTyped/pull/24509#issuecomment-382213106),它从来没有“点击”过我。但我只是遵循了指令,因为我有什么资格不同意那些对 React 和上下文略知一二的人呢?你对 KCD 的引用(~“像你运行的那样测试”)让我意识到“defaultValue”有什么问题:它允许“坏”开发者渲染依赖于上下文但不提供上下文的组件,同时惩罚那些“好”开发者正确构建他们的应用程序。 (2认同)