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

2020/10/03 17:41 · javascript ·  · 0评论

说我有以下几点:

export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
  return {
    type: SOME_ACTION,
  }
}

在该动作创建者中,我想访问全局商店状态(所有reducer)。这样做更好吗?

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的创建者Dan Abramov认为应该限制它:“我认为可以接受的几种用例是在发出请求之前检查缓存的数据,或者检查您是否已通过身份验证(换句话说,进行有条件的分发)。我认为,通过数据state.something.items在行动的创建者绝对是一个反模式和气馁,因为它掩盖了改变历史:如果有一个错误,items是不正确的,这是很难追查,其中那些不正确的值来自于,因为它们是已经是动作的一部分,而不是由减速器直接对动作进行计算。因此,请谨慎操作。”
  • 目前Redux的维护者Mark Erikson说,这很好,甚至鼓励getState在thunk中使用-这就是它存在的原因他在博客文章“惯用的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,
  }
}

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

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

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

    dispatch(anotherAction(items));
  }
}

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

理想情况下,您的操作不应是“胖子”,并且应包含尽可能少的信息,但是您应该随意在自己的应用程序中进行最适合自己的事情。的终极版FAQ对信息行动的创作者和减速器之间拆分逻辑时间时,它可以是使用有用的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需要触发多项操作

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

我同意@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);

我想指出的是,从商店中读取并没有那么糟糕-基于商店确定应该做什么比将所有内容传递给组件然后作为参数传递要方便得多。一个功能。我完全同意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())
    };
  },
});

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

提出解决此问题的另一种方法。根据您的应用,这可能比Dan的解决方案更好或更糟。

通过将动作分为2个单独的功能,您可以将状态从化简器转换为动作:首先索要数据,其次对数据进行动作。您可以使用来做到这一点redux-loop

首先“请提供数据”

export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
    return {
        type: SOME_ACTION,
    }
}

在化简器中,使用截取询问并将数据提供给第二阶段操作redux-loop

import { loop, Cmd } from 'redux-loop';
const initialState = { data: '' }
export default (state=initialState, action) => {
    switch(action.type) {
        case SOME_ACTION: {
            return loop(state, Cmd.action(anotherAction(state.data))
        }
    }
}

掌握了数据,即可完成您最初想要做的一切

export const ANOTHER_ACTION = 'ANOTHER_ACTION';
export function anotherAction(data) {
    return {
        type: ANOTHER_ACTION,
        payload: data,
    }
}

希望这对某人有帮助。

我知道我在这里参加晚会很晚,但是我来到这里是出于自己对在行动中运用国家的愿望的看法,然后当我意识到自己认为正确的行为时就形成了自己的观点。

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

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

感觉就像泄漏了抽象,但是您的组件显然需要发送一条消息,并且消息有效负载应包含相关状态。不幸的是,您的问题没有具体的示例,因为我们可以通过这种更好的选择器和操作模型来工作。

我想建议我找到最干净的另一种替代方法,但是它需要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);

如果要重用,则必须提取特定的mapStatemapDispatch并将其提取mergeProps到要在其他地方重用的函数中,但这会使依赖关系变得非常清晰。

我不会在动作创建者中访问状态。我将使用mapStateToProps()并导入整个状态对象,并import * from './reducers';在Action Creator最终要使用的组件中导入CombinedReducer文件(或)。然后在组件中使用分解以使用状态道具中需要的任何东西。如果Action Creator将状态传递给给定的TYPE的Reducer,则无需提及state,因为reducer可以访问当前设置为state的所有内容。您的示例没有更新任何内容。我只会使用Action Creator从其参数传递状态。

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

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

如果您需要对所引用的TYPE的状态执行操作,请在reducer中进行操作。

如果我错了,请指正我!!!

本文地址:http://javascript.askforanswer.com/zaidongzuochuangjianzhezhongfangwenreduxzhuangtai.html
文章标签: ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!