この記事は composer によって書かれたもので、React Context Composer を段階的にカプセル化する方法を紹介するチュートリアル コラムです。
React Context Composer を段階的にカプセル化するにはどうすればよいですか?
モチベーション
React の状態管理ソリューションは Redux、Mobx、Recoil など多数あります。これまで私は Redux しか経験したことがありませんでしたが、まだ少し面倒だと思います。私は通常、多くのフックを作成するため、useContext フックを備えた Context Provider を使用することを好みます。これにより、状態の分割と結合が簡単になります。ここでは、各状態管理ソリューションの長所と短所については説明しませんが、Context を使用するときに発生する多層ネストの問題に焦点を当てます。
下の図は、私が最近書いていた taro 反応フック ts プロジェクトから抽出したコードです。いくつかのグローバル状態を分割し (分割の目的は不必要な再レンダリングを減らすことです)、それらをネストしました。この書き方はコールバック地獄に支配されているような感覚を思い出させ、非常に不快です。そこで、自分で上位コンポーネントを封印し、記述上の構造を「フラット化」することを考えました。
<LoadingContext.Provider value={{ loading, setLoading }}> <UserDataContext.Provider value={{ name: "ascodelife", age: 25 }}> <ThemeContext.Provider value={"light"}> {/* ....more Providers as long as you want */} </ThemeContext.Provider> </UserDataContext.Provider> </LoadingContext.Provider>
最も簡単な解決策
ここでは、reduceRight を使用して Provider のネストを完了する最初の解決策を簡単に作成しました。
ここで、reduce の代わりに ReduceRight が使用されている理由は、外側の層から内側の層への書き込み順序により慣れているためです。
// ContextComposer.tsx import React from 'react'; type IContextComposerProps = { contexts: { context: React.Context<any>; value: any }[]; }; const ContextComposer: React.FC<IContextComposerProps> = ({ contexts, children }) => { return ( <> {contexts.reduceRight((child, parent) => { const { context, value } = parent; return <context.Provider value={value}>{child}</context.Provider>; }, children)} </> ); }; export default ContextComposer; // App.tsx <ContextComposer contexts={[ { context: ThemeContext, value: "light" }, { context: UserDataContext, value: { name: "ascodelife", age: 25 } }, { context: LoadingContext, value: { loading, setLoading } }, ]}> { children } </ContextComposer>
実際に体験してみると、使えるものの、開発体験は少し悪いことが分かりました。問題は、コンポーネントがパラメーターに入るときに渡される値の型が any であることです。これは、 ts の静的型チェックが放棄されていることを意味します。パラメーターを渡すとき、値に対して静的型チェックが行われないため、コードを入力するときにコード プロンプトが表示されないだけでなく、比較的低レベルのランタイム エラーが発生する可能性があります。悪いレビュー!
React.cloneElement() に基づく変換計画
#上記のスキームを変換するために、比較的不人気ではあるが使いやすい関数に注目しました— React.cloneElement().この関数について注目すべき点はそれほど多くありません。主に 3 つの入力パラメータを見てください。最初のパラメータは親要素、2 番目は親のプロパティ、3 番目は残りのパラメータ (子を除く) です。最初のパラメータ。これを除き、他のすべての値はオプションです。
例:
<!-- 调用函数 --> React.cloneElement(<div/>,{},<span/>); <!-- 相当于创建了这样一个结构 --> <div> <span></span> </div>
次に、変換を開始しましょう。reduceRight フレームは変更されません。入力パラメータのタイプとreduceRight コールバックを変更します。
// ContextComposer.tsx import React from 'react'; type IContextComposerProps = { contexts: React.ReactElement[]; }; const ContextComposer: React.FC<IContextComposerProps> = ({ contexts, children }) => { return ( <> {contexts.reduceRight((child, parent) => { return React.cloneElement(parent,{},child); }, children)} </> ); }; export default ContextComposer; // App.tsx <ContextComposer contexts={[ <ThemeContext.Provider value={"light"} />, <UserDataContext.Provider value={{ name: "ascodelife", age: 25 }} />, <LoadingContext.Provider value={{ loading, setLoading }} />, ]}> { children } </ContextComposer>
変換後、パラメーターを渡すと、実際にコンポーネントを作成しているように見えます (もちろん、コンポーネントは実際に作成されますが、コンポーネント自体は仮想 Dom にレンダリングされず、実際にはレンダリングされます。クローンコピーです)。同時に、先ほど注目した値の静的型チェックの問題も解決されました。
ヒント: React.cloneElement(parent,{},child) は React.cloneElement(parent,{children:child}) と同等ですが、その理由はわかりますか?
関連リソース
ソース コードは github (https://github.com/ascodelife/react-context-provider-composer) に同期されています。
これは、npm ウェアハウス (https://www.npmjs.com/package/@ascodelife/react-context-provider-composer) にもパッケージ化されています。ぜひ体験してください。
以上がReact Context Composer をカプセル化するための詳細な手順 (共有)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。