ストアへのアクセス
React Redux は、コンポーネントがアクションをディスパッチし、ストアからのデータ更新をサブスクライブできるようにする API を提供します。
その一環として、React Redux は、どのストアを使用しているか、およびそのストアのやり取りがどのように処理されるかの詳細を抽象化します。一般的な使用法では、独自のコンポーネントがこれらの詳細を気にする必要はなく、ストアを直接参照することはありません。React Redux は、ストアと状態が接続されたコンポーネントにどのように伝播されるかの詳細も内部的に処理するため、これはデフォルトで期待どおりに動作します。
ただし、ストアと状態が接続されたコンポーネントにどのように伝播されるかをカスタマイズしたり、ストアに直接アクセスしたりする必要がある特定のユースケースがある場合があります。以下に、その方法のいくつかの例を示します。
コンテキストの使用法を理解する
内部的には、React Redux は React の「コンテキスト」機能を使用して、Redux ストアを深くネストされた接続されたコンポーネントからアクセスできるようにします。React Redux バージョン 6 以降、これは通常、React.createContext()
によって生成される ReactReduxContext
と呼ばれる単一のデフォルトコンテキストオブジェクトインスタンスによって処理されます。
React Redux の <Provider>
コンポーネントは、<ReactReduxContext.Provider>
を使用して、Redux ストアと現在のストアの状態をコンテキストに配置し、connect
は useContext(ReactReduxContext)
を使用してこれらの値を読み取り、更新を処理します。
useStore
フックの使用
useStore
フックは、デフォルトの ReactReduxContext
から現在のストアインスタンスを返します。本当にストアにアクセスする必要がある場合は、これが推奨されるアプローチです。
カスタムコンテキストの提供
React Redux からのデフォルトのコンテキストインスタンスを使用する代わりに、独自のカスタムコンテキストインスタンスを提供できます。
<Provider context={MyContext} store={store}>
<App />
</Provider>
カスタムコンテキストを提供する場合、React Redux は、デフォルトで作成およびエクスポートするコンテキストインスタンスの代わりに、そのコンテキストインスタンスを使用します。
カスタムコンテキストを <Provider />
に提供したら、同じストアに接続すると予想されるすべての接続されたコンポーネントに、このコンテキストインスタンスを提供する必要があります。
// You can pass the context as an option to connect
export default connect(
mapState,
mapDispatch,
null,
{ context: MyContext }
)(MyComponent)
// or, call connect as normal to start
const ConnectedComponent = connect(
mapState,
mapDispatch
)(MyComponent)
// Later, pass the custom context as a prop to the connected component
<ConnectedComponent context={MyContext} />
React Redux が検索しているコンテキストにストアが見つからない場合、次のランタイムエラーが発生します。例えば
- カスタムコンテキストインスタンスを
<Provider />
に提供しましたが、接続されたコンポーネントに同じインスタンスを提供しなかった(または何も提供しなかった)。 - カスタムコンテキストを接続されたコンポーネントに提供しましたが、
<Provider />
に同じインスタンスを提供しなかった(または何も提供しなかった)。
不変違反
"Connect(MyComponent)"のコンテキストで「store」が見つかりませんでした。ルートコンポーネントを
<Provider>
でラップするか、カスタムの React コンテキストプロバイダーを<Provider>
に渡し、Connect(Todo) の接続オプションに対応する React コンテキストコンシューマーを渡してください。
カスタムコンテキストと hooks API
hooks API を介してカスタムコンテキストにアクセスするには、フッククリエーター関数を介してカスタムフックを作成できます。
複数のストア
Redux は単一のストアを使用するように設計されています。ただし、複数のストアを使用する必要がある避けられない状況にある場合は、v6 以降では、(複数の)カスタムコンテキストを提供することで実行できます。これにより、ストアが個別のコンテキストインスタンスに存在するため、ストアの自然な分離も提供されます。
// a naive example
const ContextA = React.createContext(null);
const ContextB = React.createContext(null);
// assuming reducerA and reducerB are proper reducer functions
const storeA = createStore(reducerA);
const storeB = createStore(reducerB);
// supply the context instances to Provider
function App() {
return (
<Provider store={storeA} context={ContextA} />
<Provider store={storeB} context={ContextB}>
<RootModule />
</Provider>
</Provider>
);
}
// fetch the corresponding store with connected components
// you need to use the correct context
connect(mapStateA, null, null, { context: ContextA })(MyComponentA)
// You may also pass the alternate context instance directly to the connected component instead
<ConnectedMyComponentA context={ContextA} />
// it is possible to chain connect()
// in this case MyComponent will receive merged props from both stores
compose(
connect(mapStateA, null, null, { context: ContextA }),
connect(mapStateB, null, null, { context: ContextB })
)(MyComponent);
ReactReduxContext
を直接使用する
まれに、独自のコンポーネントで Redux ストアに直接アクセスする必要がある場合があります。これは、適切なコンテキストコンシューマーを自分でレンダリングし、コンテキスト値から store
フィールドにアクセスすることで実行できます。
これは、React Redux のパブリック API の一部とは見なされず、予告なしに破損する可能性があります。コミュニティにはこれが必要なユースケースがあることを認識しており、ユーザーが React Redux の上に機能を追加できるように努めますが、コンテキストの具体的な使用は実装の詳細と見なされます。現在の API で十分にカバーされていないユースケースがさらにある場合は、API の改善の可能性について議論するために問題を提出してください。
import { ReactReduxContext } from 'react-redux'
// Somewhere inside of a <Provider>
function MyConnectedComponent() {
// Access the store via the `useContext` hook
const { store } = useContext(ReactReduxContext)
// alternately, use the render props form of the context
/*
return (
<ReactReduxContext.Consumer>
{({ store }) => {
// do something useful with the store, like passing it to a child
// component where it can be used in lifecycle methods
}}
</ReactReduxContext.Consumer>
)
*/
}
参考資料
- CodeSandbox の例:別のストアを使用するテーマ付きの読書リストアプリ(複数の)カスタムコンテキストを提供することによって実装されています。
- 関連する問題