【问题标题】:How to handle dependent action creators in Redux?如何处理 Redux 中的依赖动作创建者?
【发布时间】:2017-06-29 09:06:45
【问题描述】:

假设我有一个 REST API 来编辑用户配置文件。 这里涉及到两种方法

  • 一种更新用户配置文件的方法;
  • 一种获取当前配置文件完成分数的方法。

当然,当用户更新他的个人资料时,我想获取完成分数。

这是我(天真的?)使用 reduxredux-thunk 动作创建者的方法

function updateProfileAction(userId, profile) {

  return function (dispatch) {
    dispatch("PROFILE_UPDATE", /*...*/)
    api.updateProfile(userId, profile)
      .then(repsonse => dispatch("PROFILE_UPDATE_SUCCESS", /*...*/))
      // ▼ triggers the action that fetch the completion score
      // this is the line that bugs me
      .then(() => fetchProfileCompletionAction(userId))
  }

}

这行让我感到不安:

  • 打破了单一职责原则udpateProfileAction 突然负责也获取完成);
  • 不是分形(如果我想添加一个依赖于配置文件更新的功能,我需要再次修改那段代码。

例如,如果出于某种原因,我不想再显示完成(比如说我删除了显示它的组件)并且忘记删除这行代码,fetchCompletion 将被触发但永远不会用于图形组件)。

我在想,也许在消耗完成被获取的组件中,我现在可以订阅商店和dispatch。这将使我能够以更具反应性的方式

进行编码
function Completion(props) {

  props.store.subscribe(state => {
    //check if profile has changed
    dispatch(fetchProfileCompletionAction(userId))
  })

  return <div> {props.completion} </div>
}

这是个好主意吗?有一个更好的方法吗?另外我猜想用这个解决方案检查相关状态是否已经改变并不是一件容易的事。

【问题讨论】:

    标签: javascript reactjs redux redux-thunk


    【解决方案1】:

    就个人而言,我更喜欢您当前的解决方案。

    我是这样想的:

    • 动作代表系统中发生的事情
    • 状态可能会因操作而改变
    • 组件订阅其呈现状态的更改

    有了这个理念,如果提出了一个没有减速器正在寻找的额外动作,也没关系。如果某些状态发生变化,没有组件将呈现,没关系。

    按照您的建议,根据您的第二个建议,将很难确定状态是否已更改,因为您将只有当前状态,而没有先前的状态来确定这一点。

    如果你确实想做这样的事情,你可以使用 componentWillReceiveProps 并将组件与 react-redux 连接起来,这样状态变化就会通过 props 进入,例如:

    class ProfileSuccessNotification extends React.Component {
    
      componentWillReceiveProps(nextProps) {
        if (!this.props.success && nextProps.success) {
          this.props.showNotification(nextProps.userId)
        }
      }
    
      render() {
        return this.props.show ? <p>{this.props.userId} fetched successfully!</p> : null
      }
    }
    
    // map from where ever in your state
    const mapStateToProps = (state) => ({
      userId: state.profile.userId,
      success: state.profile.loaded,
      show: state.profileNotification.show
    })
    
    const mapDispatchToProps = (dispatch) => ({
      showNotification: (userId) => dispatch(fetchProfileCompletionAction(userId))
    })
    
    export default connect(mapStateToProps, mapDispatchToProps)(ProfileSuccessNotification)
    

    当然,你也可以让多个 reducer 对同一个动作做出反应。我不确定PROFILE_UPDATE_SUCCESSfetchProfileCompletionAction 提出的动作之间有什么区别,所以也许你只想在PROFILE_UPDATE_SUCCESS 被提出时更新两个状态,不需要再链接一秒钟完全行动。

    【讨论】:

    • 感谢您的回复 :) 我理解您的观点,我有一个非常被动的前卫背景,这种事情真的让我很烦恼。它打破了单一责任原则,完全不是分形(这意味着如果我想根据配置文件添加一个新功能,它不能是独立的,我需要更改那段代码)。另外我不是在render 中调度,而是在store.subscribe 回调中调度,这是非常不同的
    • 我意识到我的问题对于 SO 来说可能过于自以为是,也许我应该关闭它,你怎么看?
    • 您没有出现在渲染中是正确的(显然今天的咖啡不够),我将编辑我的答案以删除它。至于结束,我不介意需要有关模式或选项的指导的问题,但我同意可能很难找到可接受的答案。
    【解决方案2】:

    所以经过一些测试和研究后,我尝试使用redux-cycles 代替redux-thunk,它可以很好地处理这类问题。

    它允许我订阅正在更改的配置文件,并在配置文件更新时向服务器请求完成。这比我在最初的问题中所做的在语义上更正确

    这是代码的样子

    function main(sources) {
      const updateProfileRequest = sources.ACTION
        .filter(action => action.type === "UPDATE_PROFILE")
        .map(action => ({ /* update profile request object */))
    
      const profileUpdateSuccess$ = sources.HTTP
        .select("profileUpdate")
        .flatten()
        // when a profile request is successful, I want to warn the store
        .map(response => ({ type: "UPDATE_PROFILE_SUCCESS", profile: response.body })
    
      const fetchCompletionRequest$ = sources.STATE
        .map(state => state.profile)
        // whenever the state changes, I want to fetch the completion
        .compose(dropRepeats())
        .mapTo({ /* fetch profile request object */ })
    
      return {
        HTTP: xs.merge(udpateProfileRequest$, fetchCompletionRequest$),
        ACTION: profileUpdateSuccess$
      }
    }
    

    redux-thunk 的语义

    在我的第一次尝试中,代码的语义是:

    当用户请求更新他的个人资料时:将更新请求发送到服务器AND当响应到达时发送profile_update_success AND 发送请求以获取新的完成值

    这就是单个组件的职责

    redux-cycles 的语义

    现在,redux-cycles 这就是我的代码的含义:

    当用户请求更新其个人资料时:将更新请求发送到服务器

    当更新配置文件响应到达时:发送UPDATE_PROFILE_SUCCESS 操作

    商店资料更新时:发送请求以获取新的完成情况

    这三个动作是完全解耦的,并且有各自的语义。

    注意第二步是“当一个更新配置文件响应到达时”而不是“当更新配置文件响应时”:)

    所以最后,我并没有解决 非分形 问题,但我认为这是redux 的本质,所以我对此无能为力,但在至少我有一个更反应灵敏的系统

    【讨论】:

      猜你喜欢
      • 2015-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-01
      • 2012-07-22
      相关资源
      最近更新 更多