在动作创建者中访问Redux状态?

ffx*_*sam 263 javascript redux

说我有以下内容:

export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
  return {
    type: SOME_ACTION,
  }
}
Run Code Online (Sandbox Code Playgroud)

在该动作创建者中,我想访问全局存储状态(所有reducers).这样做更好:

import store from '../store';

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

或这个:

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

    dispatch(anotherAction(items));
  }
}
Run Code Online (Sandbox Code Playgroud)

Dan*_*mov 459

关于在动作创作者中访问状态是否是一个好主意,存在不同的意见.我认为可接受的少数用例是在您发出请求之前检查缓存数据,或者检查您是否经过身份验证(换句话说,执行条件派遣).我认为,通过数据state.something.items在行动的创建者绝对是一个反模式和气馁,因为它掩盖了改变历史:如果有一个错误,items是不正确的,这是很难追查,其中那些不正确的值来自于,因为它们是已经是动作的一部分,而不是由reducer直接计算以响应动作.所以要小心这样做.(有关在动作创建者中访问状态的利弊的进一步讨论,请参阅博客文章惯用的Redux:关于Thunk,Sagas,Abstraction和Reusability的思考.)

如果您发现需要这个,那么您建议的两种方法都可以.第一种方法不需要任何中间件:

import store from '../store';

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

但是你可以看到它依赖于getState从某个模块导出的单例.我们不建议这样做,因为它使服务器渲染添加到您的应用程序更加困难,因为在大多数情况下,在服务器上,您希望每个请求都有一个单独的存储.因此,虽然从技术上讲这种方法有效,但我们不建议从模块中导出商店.

这就是我们推荐第二种方法的原因:

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

    dispatch(anotherAction(items));
  }
}
Run Code Online (Sandbox Code Playgroud)

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

理想情况下,您的行为不应该"胖",并且应该包含尽可能少的信息,但您应该随意在自己的应用程序中做最适合您的操作.的终极版FAQ对信息行动的创作者和减速器之间拆分逻辑时间时,它可以是使用有用的store一个动作的创造者.

  • 可以从动作创建者的商店中读取.我鼓励你[使用选择器](https://egghead.io/lessons/javascript-redux-colocating-selectors-with-reducers),这样你就不依赖于确切的状态形状. (35认同)
  • 在组件中选择某些内容时,我有一种情况可能会触发PUT或POST,具体取决于商店是否包含与组件相关的数据.将PUT/POST选择的业务逻辑放在组件而不是基于thunk的动作创建器中更好吗? (4认同)
  • 最佳做法是什么?我现在在动作创建者中使用getState时遇到了类似的问题。就我而言,我使用它来确定表单中是否有待更改的值(如果是,那么我将调度一个显示对话框的操作)。 (2认同)
  • 我正在使用中间件将数据发送到mixpanel.所以我在动作中有一个元键.我需要将不同的变量从状态传递到mixpanel.在动作创建者上设置它们似乎是一种反模式.处理这类用例的最佳方法是什么? (2认同)
  • 天啊!我没想到redux thunk会接收`getState`作为第二个参数,我真是头疼,非常感谢 (2认同)

Nou*_*our 28

当您的场景很简单时,您可以使用

import store from '../store';

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

但有时你action creator需要触发多项行动

例如异步请求所以你需要 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
                });
            }
        })
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:你需要redux-thunk来在动作创建者中返回功能

  • 我可以问一下是否应检查状态'loading'的状态,以便在第一个完成时不会发出另一个ajax请求? (3认同)

Jas*_*orn 5

我同意@Bloomca。将 store 所需的值作为参数传递给 dispatch 函数似乎比导出 store 更简单。我在这里做了一个例子:

import React from "react";
import {connect} from "react-redux";
import * as actions from '../actions';

class App extends React.Component {

  handleClick(){
    const data = this.props.someStateObject.data;
    this.props.someDispatchFunction(data);
  }

  render(){
    return (
      <div>       
      <div onClick={ this.handleClick.bind(this)}>Click Me!</div>      
      </div>
    );
  }
}


const mapStateToProps = (state) => {
  return { someStateObject: state.someStateObject };
};

const mapDispatchToProps = (dispatch) => {
  return {
    someDispatchFunction:(data) => { dispatch(actions.someDispatchFunction(data))},

  };
}


export default connect(mapStateToProps, mapDispatchToProps)(App);
Run Code Online (Sandbox Code Playgroud)