如何通过 Redux 触发 AJAX 调用以响应状态变化? [英] How to fire AJAX calls in response to the state changes with Redux?

查看:22
本文介绍了如何通过 Redux 触发 AJAX 调用以响应状态变化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将现有的状态模型转换为 Redux,并且在大多数情况下都没有痛苦.但是,我遇到的问题之一是转换观察到的"状态 ajax 请求.本质上,我有某些 ajax 请求链接"到其他状态部分,所以无论谁修改它们,它们总是会正确发出.我可以通过订阅 Redux 存储更新来获得类似的行为,但在侦听器中触发操作感觉像是一种黑客行为.

I'm converting an existing state model to Redux and it has been painless for the most part. However the one point I'm having trouble with is converting "observed" state ajax requests. Essentially, I have certain ajax requests "linked" to other pieces of state, so no matter who modifies them they'll always be issued correctly. I can get similar behavior by subscribing to the Redux store updates, but firing actions in the listener feels like a hack.

一个可能的解决方案是通过 thunk 模式将逻辑移动到动作创建者.问题是我要么必须在动作之间复制获取逻辑(因为多个动作可以修改观察到的"状态),要么将大多数减速器逻辑拉到动作创建者级别.动作创建者也不应该知道减速器将如何响应发出的动作.

A possible solution is to move logic to the action creator via the thunk pattern. Problem is that I'd either have to duplicate fetching logic across actions (since multiple actions could modify "observed" state), or pull most reducer logic to the action creator level. The action creator also shouldn't be aware of how the reducers will respond to issued actions.

我可以批处理子动作",所以我只需要在每个动作块"中放置适当的获取逻辑,但这似乎违反了产生有效状态的动作的概念.我宁愿在操作创建者级别承担此责任.

I could batch "sub-actions" so I only need to place the appropriate fetching logic in each action "block", but this seems to violate the concept of actions producing a valid state. I'd rather have this liability at the action creator level.

是否有任何普遍接受的规则?这不是一个简单的应用程序,其中在与组件交互时发出临时 ajax 请求,大多数数据在多个组件之间共享,并且请求被优化和获取以响应状态变化.

Are there any generally accepted rules surrounding this? This is not a simple application where ad hoc ajax requests are made as components are interacted with, most data is shared between multiple components and requests are optimized and fetched in reaction to state change.

TLDR;我想触发 ajax 请求以响应状态变化,而不是在发生特定操作时.除了在订阅侦听器中触发这些操作之外,是否有更好的Redux 特定"方式来组织 action/actionCreators 来模拟这种行为?

TLDR; I want to fire ajax requests in response to changes in state, not when a specific action happens. Is there a better, "Redux specific" way of organizing action/actionCreators to mock this behavior, other than firing these actions in a subscribe listener?

推荐答案

Using store.subscribe()

最简单的方法是简单地使用 store.subscribe() 方法:

let prevState
store.subscribe(() => {
  let state = store.getState()

  if (state.something !== prevState.something) {
    store.dispatch(something())
  }

  prevState = state
})

您可以编写自定义抽象,让您注册副作用的条件,以便更明确地表达它们.

You can write a custom abstraction that lets you register conditions for side effects so they are expressed more declaratively.

您可能想查看 Redux Loop,它可以让您描述效果(例如 AJAX) 调用一起,并在您的减速器中进行状态更新.

You might want to look at Redux Loop which let you describe effects (such as AJAX) calls together with state updates in your reducers.

通过这种方式,您可以返回"这些效果以响应某些操作,就像您当前返回下一个状态一样:

This way you can "return" those effects in response to certain actions just like you currently return the next state:

export default function reducer(state, action) {
  switch (action.type) {
    case 'LOADING_START':
      return loop(
        { ...state, loading: true },
        Effects.promise(fetchDetails, action.payload.id)
      );

    case 'LOADING_SUCCESS':
      return {
        ...state,
        loading: false,
        details: action.payload
      };

这种方法的灵感来自 Elm 架构.

This approach is inspired by the Elm Architecture.

您还可以使用 Redux Saga 来编写长时间运行的进程(sagas") 可以采取动作,执行一些异步工作,并将结果动作放到存储中.Sagas 观察特定的动作而不是状态更新,这不是你所要求的,但我想我还是会提到它们以防万一.它们非常适合复杂的异步控制流和并发.

You can also use Redux Saga that lets you write long-running processes ("sagas") that can take actions, perform some asynchronous work, and put result actions to the store. Sagas watch specific actions rather than state updates which is not what you asked for, but I figured I’d still mention them just in case. They work great for complicated async control flow and concurrency.

function* fetchUser(action) {
   try {
      const user = yield call(Api.fetchUser, action.payload.userId);
      yield put({type: "USER_FETCH_SUCCEEDED", user: user});
   } catch (e) {
      yield put({type: "USER_FETCH_FAILED",message: e.message});
   }
}

function* mySaga() {
  yield* takeEvery("USER_FETCH_REQUESTED", fetchUser);
}

没有一个真正的方法

所有这些选项都有不同的权衡.有时人们会使用一两个,甚至全部三个,这取决于测试和描述必要逻辑最方便的方式.我鼓励您尝试所有三个并选择最适合您的用例的方法.

 No One True Way

All these options have different tradeoffs. Sometimes people use one or two, or even all three of them, depending on what turns out to be most convenient for testing and describing the necessary logic. I encourage you to try all three and pick what works best for your use case.

这篇关于如何通过 Redux 触发 AJAX 调用以响应状态变化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆