访问商店
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
Hook
The useStore
hook 从默认的 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>
,并将相应的 React 上下文消费者传递给 connect 选项中的 Connect(Todo)。
自定义上下文和钩子 API
要通过钩子 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。这可以通过自己渲染相应的 context 消费者并从 context 值中访问 store
字段来实现。
这不被认为是 React Redux 公共 API 的一部分,可能会在未经通知的情况下发生变化。我们认识到社区有一些用例需要这样做,并将努力使用户能够在 React Redux 之上构建额外的功能,但我们对 context 的具体使用被认为是实现细节。如果您有当前 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 示例:使用单独 store 的主题阅读列表应用程序,通过提供(多个)自定义 context 实现。
- 相关问题