簡體   English   中英

默認值的 React.createContext 點?

[英]React.createContext point of defaultValue?

React 16 Context doc page 上,他們有類似這樣的例子:

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

const startingValue = 'light';
const App = () => (
  <SomeContext.Provider theme={startingValue}>
    Content
  </SomeContext.Provider>
)

似乎 defaultValue 沒有用,因為如果您將startingValue設置為其他任何內容或不設置它(這是undefined ),它會覆蓋它。 沒關系,它應該這樣做。

但是defaultValue什么意義呢?

如果我想要一個不會改變的靜態上下文,那么能夠只執行以下操作並且讓 Provider 傳遞defaultValue就好了

const App = () => (
  <SomeContext.Provider>
    Content
  </SomeContext.Provider>
)

當沒有 Provider 時,defaultValue 參數用於函數 createContext。 這有助於在不包裝組件的情況下單獨測試組件,或使用來自 Provider 的不同值對其進行測試。


代碼示例:

import { createContext, useContext } from "react";

const Context = createContext( "Default Value" );

function Child() {
  const context = useContext(Context);
  return <h2>Child1: {context}</h2>;
}

function Child2() {
  const context = useContext(Context);
  return <h2>Child2: {context}</h2>;
}

function App() {

  return (
    <>
      <Context.Provider value={ "Initial Value" }>
        <Child /> {/* Child inside Provider will get "Initial Value" */}
      </Context.Provider>
        <Child2 /> {/* Child outside Provider will get "Default Value" */}
    </>
  );
}

代碼沙盒演示

我的兩分錢:

像往常一樣閱讀 Kent C. Dodds 撰寫這篇有啟發性的文章:) 后,我了解到當您解構 useContext 返回的值時, defaultValue 很有用:

在沒有 defaultValue 的代碼庫的一角定義上下文:

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

並在組件中像這樣使用它:

const { count } = React.useContext(CountStateContext)

JS 很明顯會說TypeError: Cannot read property 'count' of undefined

但是你不能這樣做,完全避免使用 defaultValue。

關於考試,我的老師 Kent 說得很好:

React 文檔建議提供默認值“有助於在不包裝組件的情況下隔離測試組件。” 雖然它確實允許您這樣做,但我不同意這比用必要的上下文包裝組件更好。 請記住,每次您在測試中做了一些您在應用程序中沒有做的事情時,都會降低測試可以提供給您的信心。

額外的打字稿 如果您不想使用 defaultValue,可以通過執行以下操作輕松取悅 lint:

const MyFancyContext = React.createContext<MyFancyType | undefined>(undefined)

您只需要確保稍后添加額外的驗證,以確保您已經涵蓋了 MyFancyContext === 未定義的情況

  • MyFancyContext ?? '默認'
  • MyFancyContext?.notThatFancyProperty

您可以使用 useReducer 鈎子設置默認值,然后第二個參數將是默認值:

import React, { createContext, useReducer } from "react";
import { yourReducer } from "./yourReducer";

export const WidgetContext = createContext();

const ContextProvider = (props) => {

  const { children , defaultValues } = props;
 
  const [state, dispatch] = useReducer(yourReducer, defaultValues);

  return (
    <WidgetContext.Provider value={{ state, dispatch }}>
      {children}
    </WidgetContext.Provider>
  );
};

export default ContextProvider;

// 實現

   <ContextProvider
                  defaultValues={{
                    disabled: false,
                    icon: undefined,
                    text: "Hello",
                    badge: "100k",
                    styletype: "primary",
                    dir: "ltr",
                    }}
                >
    </ContextProvider>
    

只是在使用 TypeScript 時分享我的典型設置,以完成上面@tiomno 的回答,因為我認為許多最終到這里的谷歌員工實際上正在尋找這個:

interface GridItemContextType {
    /** id of the item = widgetId-occurence_nb (same widget can appear twice in the layout) */
    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 as GridItemContextType;
};

在這種情況下,鈎子提供了更安全的輸入。 undefined defaultValue可防止您忘記設置提供程序。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM