访问存储
¥Accessing the Store
React Redux 提供的 API 允许你的组件分派操作并从存储订阅数据更新。
¥React Redux provides APIs that allow your components to dispatch actions and subscribe to data updates from the store.
作为其中的一部分,React Redux 抽象出了你正在使用的存储的详细信息,以及如何处理该存储交互的确切细节。在典型用法中,你自己的组件永远不需要关心这些细节,并且永远不会直接引用存储。React Redux 还在内部处理存储和状态如何传播到连接的组件的详细信息,以便默认情况下按预期工作。
¥As part of that, React Redux abstracts away the details of which store you are using, and the exact details of how that store interaction is handled. In typical usage, your own components should never need to care about those details, and won't ever reference the store directly. React Redux also internally handles the details of how the store and state are propagated to connected components, so that this works as expected by default.
但是,在某些用例中,你可能需要自定义将存储传递给连接组件的方式,或者直接访问存储。以下是如何执行此操作的一些示例。
¥However, there may be certain use cases where you may need to customize how the store is passed to connected components, or access the store directly. Here are some examples of how to do this.
了解上下文用法
¥Understanding Context Usage
在内部,React Redux 使用 React 的 "context" 功能 使 Redux 存储可供深度嵌套的连接组件访问。从 React Redux 版本 6 开始,这通常由 React.createContext()
生成的单个默认上下文对象实例(称为 ReactReduxContext
)处理。
¥Internally, React Redux uses React's "context" feature to make the
Redux store accessible to deeply nested connected components. As of React Redux version 6, this is normally handled
by a single default context object instance generated by React.createContext()
, called ReactReduxContext
.
React Redux 的 <Provider>
组件使用 <ReactReduxContext.Provider>
将 Redux 存储和内部订阅封装器放入上下文中。useSelector
、useDispatch
和 connect
调用 useContext(ReactReduxContext)
来读取这些值并处理更新。
¥React Redux's <Provider>
component uses <ReactReduxContext.Provider>
to put the Redux store and internal subscription wrappers into context. useSelector
, useDispatch
, and connect
call useContext(ReactReduxContext)
to read those values and handle updates.
使用 useStore
钩子
¥Using the useStore
Hook
useStore
钩 从默认的 ReactReduxContext
返回当前存储实例。如果你确实需要访问存储,这是推荐的方法。
¥The useStore
hook returns the current store instance from the default ReactReduxContext
. If you truly need to access the store, this is the recommended approach.
提供自定义上下文
¥Providing Custom Context
你可以提供自己的自定义上下文实例,而不是使用 React Redux 中的默认上下文实例。
¥Instead of using the default context instance from React Redux, you may supply your own custom context instance.
<Provider context={MyContext} store={store}>
<App />
</Provider>
如果你提供自定义上下文,React Redux 将使用该上下文实例,而不是默认创建和导出的实例。
¥If you supply a custom context, React Redux will use that context instance instead of the one it creates and exports by default.
向 <Provider />
提供自定义上下文后,你需要将此上下文实例提供给所有预计连接到同一存储的已连接组件:
¥After you’ve supplied the custom context to <Provider />
, you will need to supply this context instance to all of your connected components that are expected to connect to the same store:
// 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 在它正在查找的上下文中找不到存储时,会发生以下运行时错误。例如:
¥The following runtime error occurs when React Redux does not find a store in the context it is looking. For example:
你向
<Provider />
提供了自定义上下文实例,但没有向连接的组件提供相同的实例(或没有提供任何实例)。¥You provided a custom context instance to
<Provider />
, but did not provide the same instance (or did not provide any) to your connected components.你向连接的组件提供了自定义上下文,但没有向
<Provider />
提供相同的实例(或没有提供任何实例)。¥You provided a custom context to your connected component, but did not provide the same instance (or did not provide any) to
<Provider />
.
不变违规
¥Invariant Violation
在 "Connect(MyComponent)" 的上下文中找不到 "store"。将根组件封装在
<Provider>
中,或者将自定义 React 上下文提供者传递给<Provider>
,并将相应的 React 上下文使用者传递给连接选项中的 Connect(Todo)。¥Could not find "store" in the context of "Connect(MyComponent)". Either wrap the root component in a
<Provider>
, or pass a custom React context provider to<Provider>
and the corresponding React context consumer to Connect(Todo) in connect options.
自定义上下文和钩子 API
¥Custom Context and the hooks API
要通过 hooks API 访问自定义上下文,你可以通过 钩子创建函数。
¥To access the custom context via the hooks API, you can create custom hooks via the hook creator functions.
多家存储
¥Multiple Stores
Redux 被设计为使用单个存储。但是,如果你不可避免地需要使用多个存储,则从 v6 开始,你可以通过提供(多个)自定义上下文来实现。这还提供了存储的自然隔离,因为它们位于不同的上下文实例中。
¥Redux was designed to use a single store. However, if you are in an unavoidable position of needing to use multiple stores, as of v6 you may do so by providing (multiple) custom contexts. This also provides a natural isolation of the stores as they live in separate context instances.
// 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
¥Using ReactReduxContext
Directly
在极少数情况下,你可能需要直接在自己的组件中访问 Redux 存储。这可以通过自己渲染适当的上下文使用者并从上下文值中访问 store
字段来完成。
¥In rare cases, you may need to access the Redux store directly in your own components. This can be done by rendering
the appropriate context consumer yourself, and accessing the store
field out of the context value.
这不被视为 React Redux 公共 API 的一部分,并且可能会中断,恕不另行通知。我们确实认识到社区有必要这样做的用例,并将尝试使用户能够在 React Redux 之上构建附加功能,但我们对上下文的具体使用被视为实现细节。如果你有当前 API 未充分涵盖的其他用例,请提交问题以讨论可能的 API 改进。
¥This is not considered part of the React Redux public API, and may break without notice. We do recognize that the community has use cases where this is necessary, and will try to make it possible for users to build additional functionality on top of React Redux, but our specific use of context is considered an implementation detail. If you have additional use cases that are not sufficiently covered by the current APIs, please file an issue to discuss possible API improvements.
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>
)
*/
}
更多资源
¥Further Resources
代码沙盒示例:使用单独存储的主题阅读列表应用,通过提供(多个)自定义上下文来实现。
¥CodeSandbox example: A reading list app with theme using a separate store, implemented by providing (multiple) custom context(s).
相关问题:
¥Related issues: