在操作创建器中访问 Redux 状态?

2022-08-29 23:41:01

假设我有以下情况:

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));
  }
}

答案 1

关于在行动中创建者访问状态是否是一个好主意,存在不同的看法:

  • Redux的创建者Dan Abramov认为它应该受到限制:“我认为可以接受的少数用例是在发出请求之前检查缓存的数据,或者检查您是否经过身份验证(换句话说,执行条件调度)。我认为传递数据(例如在操作创建者中)绝对是一种反模式,并且不鼓励这样做,因为它掩盖了更改历史记录:如果存在错误并且不正确,则很难跟踪这些不正确的值的来源,因为它们已经是操作的一部分,而不是由化简器直接计算以响应操作。所以要小心。state.something.itemsitems
  • 目前的 Redux 维护者 Mark Erikson 说这很好,甚至鼓励在 thunks 中使用 getState - 这就是它存在的原因。他在他的博客文章 Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability 中讨论了在行动中创建者访问状态的优缺点。

如果您发现自己需要此功能,则您建议的两种方法都可以。第一种方法不需要任何中间件:

import store from '../store';

export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
  return {
    type: SOME_ACTION,
    items: store.getState().otherReducer.items,
  }
}

但是,您可以看到它依赖于从某些模块导出的单例。我们不建议这样做,因为这会使向应用添加服务器呈现变得更加困难,因为在大多数情况下,在服务器上,你希望每个请求都有一个单独的存储。因此,虽然从技术上讲此方法有效,但我们不建议从模块导出存储。store

这就是为什么我们推荐第二种方法:

export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
  return (dispatch, getState) => {
    const {items} = getState().otherReducer;

    dispatch(anotherAction(items));
  }
}

它需要您使用 Redux Thunk 中间件,但它在客户端和服务器上都可以正常工作。您可以在此处阅读有关Redux Thunk的更多信息,以及为什么在这种情况下有必要这样做。

理想情况下,您的操作不应该是“胖子”,并且应该包含尽可能少的信息,但是您应该在自己的应用程序中随意做最适合您的操作。Redux FAQ 提供了有关在操作创建者和化简器之间拆分逻辑的信息,以及在操作创建者中使用 getState 可能有用的时间


答案 2

当你的方案很简单时,你可以使用

import store from '../store';

export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
  return {
    type: SOME_ACTION,
    items: store.getState().otherReducer.items,
  }
}

但有时您需要触发多个操作action creator

例如,异步请求,因此您需要操作REQUEST_LOADREQUEST_LOAD_SUCCESSREQUEST_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 才能在操作创建器中返回函数