はい
reactのcontextは便利です。Reduxキラーとして君臨し、多くの開発者を苦しめてきました。特にhooksが登場してからというもの、useContext()
によりその利便性はさらに高くなりました。
const {data} = useContext(DataContext);
あるいは
<DataContext.Consumer>
{({data}) => /* render something */}
</DataContext.Consumer>
さて、このときDataContext.Provider
以下でこれらが呼び出されることを保証できるでしょうか?結論から言うとできません。TypeScriptにおいても同様です(そりゃそうだ)
ちなみに、ProviderがなければcreateContextのデフォルト値がそのまま利用できます。
const DataContext = createContext({ hai: "haijanaiga" } as
{
hai: string
});
export default App: React.FC = () => {
const data = useContext(DataContext);
return <h1>{data.hai}</h1>;
}; // its equally `<h1>haijanaiga</h1>`
しかし、たいていの場合において<Context.Consumer />
およびuseContext()
はProvider以下で呼びたいことが殆どでしょう。
しかし、Reactはこのときエラーになってくれません。デフォルト値が存在するためです。
また、ほとんどの場合開発時にのみ問題になりうるものですから、そのときにエラーになってくれればよいものです。すると、次のようなコードを書くことになるでしょう…
type SomeContextType = {
hai: string
}
const DataContext = createContext(undefined as undefined | SomeContextType);
const DataProvider = DataContext.Provider;
const useDataCtx = (): SomeContextType | never => {
const ctx = useContext(DataContext);
if (!ctx) throw new Error("Not children of DataContext.Provider")
return ctx;
}
このとき、<DataProvider state={{hai: ""}}>
がない状態でuseDataCtx()
が呼び出されても、適正にエラーが送出されるため、健全性が高まると言えます。
あるいは、非同期処理を利用などの理由でわざとundefined
を挿入しているとしても、if (typeof ctx === "undefined")
などで代替し、読み込みの状態についてはnull
を注入することもできます。もっとも、nullを注入するような行為は健全性に欠けますが…
単純に考えましょう。読み込み中であるstateたとえば{suspending: true}
をProviderに注入する方法が効きます。
ところであなたのContextは健全ですか?
Top comments (0)