如何处理Redux中的依赖动作创建者?

时间:2017-06-29 09:06:45

标签: javascript reactjs redux redux-thunk

我们说我有一个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>
}

这是个好主意吗?有一个更好的方法吗?此外,我想检查相关状态已经发生变化对于这个解决方案来说并不是真的微不足道。

2 个答案:

答案 0 :(得分:3)

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

我想起来就像这样:

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

有了这个理念,如果提出一个额外的行动,没有减速器正在寻找,那么无关紧要。如果某些状态发生变化,没有任何组件会呈现,那么无关紧要。

根据你的建议,根据你的第二个建议,很难确定状态是否已经改变,因为你只有当前状态而没有以前的状态来确定。

如果您确实想要这样做,可以使用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被提升时更新2个状态,根本不需要连接第二个动作。

答案 1 :(得分: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操作

更新商店的个人资料:发送请求以获得新的完成

这三个动作完全分离,并且具有单独的语义。

注意第二步是&#34;当 更新配置文件响应到达时#34;而不是&#34;当 更新个人资料回复&#34; :)

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