假设我有以下内容:

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

当前回答

I wouldn't access state in the Action Creator. I would use mapStateToProps() and import the entire state object and import a combinedReducer file (or import * from './reducers';) in the component the Action Creator is eventually going to. Then use destructuring in the component to use whatever you need from the state prop. If the Action Creator is passing the state onto a Reducer for the given TYPE, you don't need to mention state because the reducer has access to everything that is currently set in state. Your example is not updating anything. I would only use the Action Creator to pass along state from its parameters.

在减速器中执行如下操作:

const state = this.state;
const apple = this.state.apples;

如果你需要对你所引用的TYPE的状态执行操作,请在减速器中执行。

如果我说错了请指正!!

其他回答

我想建议另一个我认为最干净的替代方案,但它需要react-redux或类似的东西-同时我还使用了其他一些奇特的功能:

// actions.js
export const someAction = (items) => ({
    type: 'SOME_ACTION',
    payload: {items},
});
// Component.jsx
import {connect} from "react-redux";

const Component = ({boundSomeAction}) => (<div
    onClick={boundSomeAction}
/>);

const mapState = ({otherReducer: {items}}) => ({
    items,
});

const mapDispatch = (dispatch) => bindActionCreators({
    someAction,
}, dispatch);

const mergeProps = (mappedState, mappedDispatches) => {
    // you can only use what gets returned here, so you dont have access to `items` and 
    // `someAction` anymore
    return {
        boundSomeAction: () => mappedDispatches.someAction(mappedState.items),
    }
});

export const ConnectedComponent = connect(mapState, mapDispatch, mergeProps)(Component);
// (with  other mapped state or dispatches) Component.jsx
import {connect} from "react-redux";

const Component = ({boundSomeAction, otherAction, otherMappedState}) => (<div
    onClick={boundSomeAction}
    onSomeOtherEvent={otherAction}
>
    {JSON.stringify(otherMappedState)}
</div>);

const mapState = ({otherReducer: {items}, otherMappedState}) => ({
    items,
    otherMappedState,
});

const mapDispatch = (dispatch) => bindActionCreators({
    someAction,
    otherAction,
}, dispatch);

const mergeProps = (mappedState, mappedDispatches) => {
    const {items, ...remainingMappedState} = mappedState;
    const {someAction, ...remainingMappedDispatch} = mappedDispatch;
    // you can only use what gets returned here, so you dont have access to `items` and 
    // `someAction` anymore
    return {
        boundSomeAction: () => someAction(items),
        ...remainingMappedState,
        ...remainingMappedDispatch,
    }
});

export const ConnectedComponent = connect(mapState, mapDispatch, mergeProps)(Component);

如果你想重用它,你必须将特定的mapState、mapDispatch和mergeProps提取到函数中,以便在其他地方重用,但这使得依赖关系非常清楚。

我想指出的是,从存储中读取数据并没有那么糟糕——根据存储决定应该做什么,可能比将所有内容都传递给组件然后作为函数的参数要方便得多。我完全同意Dan的观点,最好不要将store单独使用,除非你100%确定只用于客户端渲染(否则很难跟踪可能出现的bug)。

我最近创建了一个库来处理redux的冗长,我认为把所有东西都放在中间件中是一个好主意,这样你就可以把所有东西都作为依赖注入。

你的例子是这样的:

import { createSyncTile } from 'redux-tiles';

const someTile = createSyncTile({
  type: ['some', 'tile'],
  fn: ({ params, selectors, getState }) => {
    return {
      data: params.data,
      items: selectors.another.tile(getState())
    };
  },
});

然而,正如您所看到的,我们在这里并没有真正修改数据,所以很有可能我们可以在其他地方使用这个选择器来组合其他地方的数据。

我知道我来这里有点晚了,但我来这里是为了表达我对在行动中使用状态的渴望,然后形成了我自己的想法,当我意识到什么是我认为正确的行为时。

这就是选择器对我最有意义的地方。发出此请求的组件应该被告知是否该通过选择发出该请求。

export const SOME_ACTION = 'SOME_ACTION';
export function someAction(items) {
  return (dispatch) => {
    dispatch(anotherAction(items));
  }
}

这可能感觉像是泄露了抽象,但是您的组件显然需要发送消息,并且消息有效负载应该包含相关的状态。不幸的是,你的问题没有一个具体的例子,因为我们可以通过一个“更好的模型”的选择器和动作。

对于在动作创建者中访问状态是否是一个好主意,有不同的意见:

Redux creator Dan Abramov feels that it should be limited: "The few use cases where I think it’s acceptable is for checking cached data before you make a request, or for checking whether you are authenticated (in other words, doing a conditional dispatch). I think that passing data such as state.something.items in an action creator is definitely an anti-pattern and is discouraged because it obscured the change history: if there is a bug and items are incorrect, it is hard to trace where those incorrect values come from because they are already part of the action, rather than directly computed by a reducer in response to an action. So do this with care." Current Redux maintainer Mark Erikson says it's fine and even encouraged to use getState in thunks - that's why it exists. He discusses the pros and cons of accessing state in action creators in his blog post 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,
  }
}

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

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

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

    dispatch(anotherAction(items));
  }
}

这需要你使用Redux坦克中间件,但它在客户端和服务器上都工作得很好。你可以阅读更多关于Redux坦克和为什么它在这种情况下是必要的在这里。

理想情况下,您的操作不应该“臃肿”,并且应该包含尽可能少的信息,但是您应该在自己的应用程序中自由地执行最适合自己的操作。Redux常见问题解答中有关于拆分操作创建者和还原器之间逻辑的信息,以及在操作创建者中使用getState可能有用的时间。

我同意@Bloomca。将存储所需的值作为参数传递给分派函数似乎比导出存储简单。我举个例子:

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