![](/img/trans.png)
[英]Is there any practical way to call `React.createContext()` within a component?
[英]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 === 未定義的情況
等
您可以使用 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.