【问题标题】:How to access redux store from action creator?如何从动作创建者访问 redux 商店?
【发布时间】:2019-06-22 22:18:03
【问题描述】:

我正在考虑尝试将操作链接在一起。在我当前的问题中,当 SET_CURRENT_USER 操作发生时,我希望它修改状态(设置当前用户),然后启动一堆其他副作用任务(去获取数据,重建 UI 等)。我的第一个想法是“好吧,我会在商店里设置一个监听器”......这导致了之前的问题:How to access 'store' in react redux? (or how to chain actions) 在那里,我基本上认为设置监听器是一种反模式。

建议的解决方案是“调度”多个链接在一起的操作。我没有遵循如何做到这一点(我的“mapDispatchToProps”基于 redux 教程,看起来与建议的 mapDispatchToProps 完全不同)所以我做了一些额外的谷歌搜索,了解如何将副作用操作链接在一起并进入此页面:@ 987654322@

尝试第一个示例,我转到了我的动作创建器文件,它看起来像这样:

(actionCreators.js)

export function setCurrentUser(username) {
    return { type: SET_CURRENT_USER, payload: username }
}

export function actionTwo(username) {
    return { type: ACTION_TWO, payload: username }
}

export function actionThree(username) {
    return { type: ACTION_THREE, payload: username }
}

我尝试将“setCurrentUser”动作创建者更改为类似于演示中的内容,但为简单起见没有异步部分 - 只是查看动作是否触发:

export function setCurrentUser(username) {
    return dispatch => {
        dispatch( { type: SET_CURRENT_USER, payload: username } );
        dispatch( { type: ACTION_TWO, payload: username } );
        dispatch( { type: ACTION_THREE, payload: username } );
    }
}

在我的应用中,我的 mapDispatchToProps 如下所示:

const mapDispatchToProps = {
    setCurrentUser: setCurrentUser,
}

我在 switchUser 处理程序中调用它,如下所示:this.props.setCurrentUser(this.state.newUsername);

...我收到一条错误消息,提示操作必须是普通对象。

如何将操作链接在一起?

也许更深层次的问题是我不知道如何访问商店才能调用 store.dispatch。 (这是我之前提到的问题)

【问题讨论】:

  • 您是否使用 thunk 作为中间件?
  • 我没有使用任何中间件(虽然可能会添加 Thunk 来做异步)
  • 我认为你需要 redux thunk 来调度多个操作
  • @lowcrawler。您需要 thunk 来增强您的动作创建者。您收到“必须是普通对象”错误的原因是您的操作创建者返回的是函数(),而不是对象。 Thunk 允许您在动作创建器中返回函数,并且使用它,您编写的代码应该可以工作。
  • 所以演示假设添加了 thunk。 @yourfavoritedev - 写下您的评论作为答案,我会将其标记为正确(假设它有效......我现在将实施)

标签: reactjs redux


【解决方案1】:

我不能发表评论,所以一个问题:你为什么不直接设置 mapState 并将状态作为参数传递给调度的动作?

这里是组件的东西

class AComponent extends Component{
     ...
     ... onClick={()=>this.props.anAction(this.props.state)}
}

const mapStateToProps = state => {
    return { state: state.YourReducer }
}

const mapDispatchToProps = dispatch => {
    return { anAction: () => dispatch(actions.doAnyStaffWith(state)) }
}

export default connect(mapStateToProps, mapDispatchToProps)(BeerReviewer)

动作文件:

export function actionThree(state) {
     return { type: ACTION_TYPE, state }
}

这就是你要找的东西?

【讨论】:

    【解决方案2】:

    Redux thunk 将是实现此目的的理想方式,但您仍然可以通过返回 Promise 作为有效负载来链接操作。(如果您不想使用 thunk)

    export function setCurrentUser(username) {
        return { 
          type: SET_CURRENT_USER, 
          payload: new Promise(resolve => resolve(username))  
        }
    } 
    
    export function actionTwo(username) {
        return { 
          type: ACTION_TWO, 
          payload: new Promise(resolve => resolve(username))  
        }
    }
    
    export function actionThree(username) {
        return { 
          type: ACTION_THREE, 
          payload: new Promise(resolve => resolve(username))  
        }
    }
    

    然后你可以像这样调用所有三个:

    this.props.setCurrentUser(this.state.newUsername)
     .then(newUsername => this.props.actionTwo(newUsername))
     .then(newUsername => this.props.actionThree(newUsername))
    

    【讨论】:

      【解决方案3】:

      您需要 thunk 来增强您的动作创建者。您收到“必须是普通对象”错误的原因是您的操作创建者返回的是函数(),而不是对象。 Thunk 允许您在动作创建器中返回函数,并且使用它,您编写的代码应该可以工作。

      import { createStore, combineReducers, applyMiddleware } from "redux"
      import thunk from "redux-thunk"
      
      const store = createStore(combineReducers({
           data1: reducer1,
           data2: reducer2
      }), {}, applyMiddleware(thunk))
      

      希望有效。

      【讨论】:

      • 值得注意的是,使用 redux devtools,我最终不得不在 createStore 过程中使用 compose
      【解决方案4】:

      您应该能够像这样访问您的商店(以获取请求为例):

      import { someAPICALL } from '../api'
      
      export function setCurrentUser(username) {
          return async (dispatch, getState) => {
              const { yourStateVariable } = getState().YourReducer
                  , data = await someAPICall(yourStateVariable)
                                 .catch(e => dispatch({ type: FETCH_ERROR, payload: e }))
      
              if (data) {
                dispatch( { type: SET_CURRENT_USER, payload: username } );
                dispatch( { type: ACTION_TWO, payload: username } );
                dispatch( { type: ACTION_THREE, payload: username } );
              } else {
                dispatch( { type: SOME_OTHER_ACTION, payload: 'whatever state update you like' } )
              }
          }
      }
      

      【讨论】:

        【解决方案5】:

        我认为你的mapDispatchToProps 函数应该是这样的:const mapDispatchToProps = { setCurrentUser: (data) => dispatch(setCurrentUser(data)), }。关于从动作创建者访问存储,您需要从声明它的位置(index.js)导出它。将其导入您的 actionCreators 文件,然后在那里使用它。它是这样的: 在 index.js 文件中:export const store = createStore(...) 和在你的 actionCreators 文件中:import { store } from "your index.js file's path",你很高兴。希望能解决您的问题。

        【讨论】:

        猜你喜欢
        • 2016-07-14
        • 2019-03-03
        • 1970-01-01
        • 2020-04-22
        • 2016-06-10
        • 2017-05-29
        • 1970-01-01
        • 1970-01-01
        • 2020-06-03
        相关资源
        最近更新 更多