在动作创build器中访问Redux状态?
说我有以下几点:
export const SOME_ACTION = 'SOME_ACTION'; export function someAction() { return { type: SOME_ACTION, } }
而在那个动作创造者,我想要访问全球商店状态(所有减速器)。 这样做更好吗:
import store from '../store'; export const SOME_ACTION = 'SOME_ACTION'; export function someAction() { return { type: SOME_ACTION, items: store.getState().otherReducer.items, } }
或这个:
export const SOME_ACTION = 'SOME_ACTION'; export function someAction() { return (dispatch, getState) => { const {items} = getState().otherReducer; dispatch(anotherAction(items)); } }
在行动创造者中获取国家是否是一个好主意,有不同的意见。 我认为可以接受的一些用例是在发出请求之前检查caching的数据,或者检查是否进行了身份validation(换句话说,执行有条件的发送)。 我认为在动作创build者中传递state.something.items
等数据肯定是一种反模式,因为它遮蔽了变化的历史,所以不鼓励:如果有错误, items
不正确,很难追查那些错误的地方价值来源于它们,因为它们已经是行动的一部分,而不是直接由减速器响应行动来计算。 所以要小心。 (关于访问动作创build者状态的利弊的进一步讨论,请参阅博客文章“ 习语Redux:关于Thunk,Sagas,Abstraction和Reusability的思考” 。
如果你发现你需要这个,你build议的两种方法都很好。 第一种方法不需要任何中间件:
import store from '../store'; export const SOME_ACTION = 'SOME_ACTION'; export function someAction() { return { type: SOME_ACTION, items: store.getState().otherReducer.items, } }
但是你可以看到它依赖于从某个模块导出的单例store
。 我们不build议这样做,因为这会使服务器渲染更难以添加到应用程序中,因为在大多数情况下,服务器上的每个请求都需要单独存储 。 所以,虽然技术上这种方法有效,但我们不build议从模块中导出商店。
这就是为什么我们推荐第二种方法:
export const SOME_ACTION = 'SOME_ACTION'; export function someAction() { return (dispatch, getState) => { const {items} = getState().otherReducer; dispatch(anotherAction(items)); } }
这将需要您使用Redux Thunk中间件,但它在客户端和服务器上都能正常工作。 你可以阅读更多关于Redux Thunk的信息,以及为什么在这里需要这个。
理想情况下,你的行为不应该是“胖”,应尽可能less的信息,但你应该自由地做你最适合自己的应用程序。 Redux常见问题解答有关于动作创build者和缩减者之间的逻辑分割的信息, 以及 在动作创build者中使用getState
可能有用的时间的信息 。
当你的情况很简单,你可以使用
import store from '../store'; export const SOME_ACTION = 'SOME_ACTION'; export function someAction() { return { type: SOME_ACTION, items: store.getState().otherReducer.items, } }
但有时你的action creator
需要触发多个动作
例如asynchronous请求,所以你需要REQUEST_LOAD
REQUEST_LOAD_SUCCESS
REQUEST_LOAD_FAIL
动作
export const [REQUEST_LOAD, REQUEST_LOAD_SUCCESS, REQUEST_LOAD_FAIL] = [`REQUEST_LOAD` `REQUEST_LOAD_SUCCESS` `REQUEST_LOAD_FAIL` ] export function someAction() { return (dispatch, getState) => { const { items } = getState().otherReducer; dispatch({ type: REQUEST_LOAD, loading: true }); $.ajax('url', { success: (data) => { dispatch({ type: REQUEST_LOAD_SUCCESS, loading: false, data: data }); }, error: (error) => { dispatch({ type: REQUEST_LOAD_FAIL, loading: false, error: error }); } }) } }
注意:您需要使用redux-thunk来返回动作创build者的function
我想指出,从商店中读取并不是什么坏事 – 根据商店来决定应该做什么可能更方便,而不是将所有内容传递给组件,然后作为参数一个function。 我完全同意Dan的观点,除非您100%确定只用于客户端渲染(否则很难追踪可能出现的错误),否则最好不要将商店用作单人游戏。
我最近创build了一个库来处理redux的冗长问题,我认为把所有东西都放在中间件中是一个好主意,所以你将everyhing作为dependency injection。
所以,你的例子将如下所示:
import { createSyncTile } from 'redux-tiles'; const someTile = createSyncTile({ type: ['some', 'tile'], fn: ({ params, selectors, getState }) => { return { data: params.data, items: selectors.another.tile(getState()) }; }, });
但是,正如您所看到的,我们并没有真正修改数据,所以我们可以在其他地方使用这个select器将其结合到别的地方。