redux reducer vs Action

标签 redux redux-thunk

关于 reducer 与 Action 的新手问题。 From redux documentation :

Actions describe the fact that something happened, but don’t specify how the application’s state changes in response.

Given the same arguments, reducer should calculate the next state and return it. No surprises. No side effects. No API calls. No mutations. Just a calculation.

因此,如果我们考虑以下场景:

  1. 用户可以在 map 上放置点并获取这些点之间的路线。
  2. 当用户第一次点击 map 时,这是他的起点。当他第二次点击时——这就是他的终点。随后的点击会在前一个点和结束位置之间添加点。
  3. 添加每个点(第一个点除外)后,必须计算新点和前一个点之间的路线。因此,如果我有 S -> A -> F 并添加点 B (S -> A -> B -> F) 必须计算两条路线 A -> B 和 B -> F

因此,在添加任何 3 个以上的点时,我们会产生两个副作用:

  • 新点未放置在列表末尾
  • 必须计算到达终点的新路线。

如果我将 Point 结构建模如下:

 // typescript
interface Point {
  coordinates;
  routeTo?;
}

我在操作中执行项目位置计算和路线检索是否正确,例如:

  // pseudo code
    export function addMapPoint(newPoint) {
      return (dispatch, getState) => {
        const {points} = getState();
        const position = getInsertPosition(points, newPoint)
        dispatch(addPoint(newPoint, position));
        if (points.length >= 2) {
          const previousPoint = getPreviousPoint(points, position);
          calculateRoute(newPoint, previousPoint).then(route => {
            dispatch(updateRoute(newPoint, route))
          })
        }
      }
    }

对我来说,这在某种程度上与“但不指定应用程序的状态如何变化”相矛盾 - 因为从操作中我指定了在哪里插入我的新点。
我可以计算reducer中的插入位置,但是如何获取终点的路线数据?
这里正确的做法是什么?

最佳答案

假设我们有 calculateRoute函数接受两个点,并返回一个解决它们之间路线的 promise 。

首先,让我们创建一个简单的 Action 创建器,以便我们知道我们的点已正确存储:

let addPoint = (point, index) => {
    return {
        type: 'ADD_POINT',
        point: point,
        index: index
    }
}

然后,让我们在reducer中处理这个 Action :

let reducer = (state = { points: [] }, action) => {
    switch (action.type) {
        case 'ADD_POINT':
            return Object.assign({}, state, {
                points: [
                    ...state.points.slide(0, action.index),
                    action.point,
                    ...state.points.slide(action.index + 1)
                ]
            });
        default:
            return state;
    }
}

现在,在用户添加点后,我们使用 addPoint 创建一个操作并发送它,到目前为止一切顺利,但这是简单的事情。

我追求的结构是在我的 reducer 中也有一个路由列表,所以让我们扩展它以支持它:

let reducer = (state = { points: [], routes: [] }, action) => {
    switch (action.type) {
        case 'ADD_POINT':
            return Object.assign({}, state, {
                points: [
                    ...state.points.slide(0, action.index),
                    action.point,
                    ...state.points.slide(action.index + 1)
                ]
            });
        case 'UPDATE_ROUTES':
            return Object.assign({}, state, {
                routes: action.routes
            });
        default:
            return state;
    }
}

Action 创建者将是:

let updateRoutes = (routes) => {
    return {
        type: 'UPDATE_ROUTES',
        routes: routes
    }
}

请注意,我们正在覆盖整个路线集合。目前还可以,但在生产系统中您可能需要对其进行一些优化。

现在我们实际上需要编写一些逻辑。我将假设一个方便的假设,即我们有 calculateRoutes获取点的集合,并返回一个解析相应路线列表的 promise ,每个路线将是一个对象,包含两个点和实际路线。话虽如此,我们的thunk现在看起来像这样:

addPointAndUpdateRoutes = (point, index) => {
    return (dispatch, getState) => {
        // First, update the point list
        dispatch(addPoint(point, index));

        // Now, recalculate routes
        calculateRoutes(getState().points)
            .then(routes => dispatch(updateRoutes(routes));
    };
};

我认为这更好。


现在,当然假设我们有一个神奇的 calculateRoutes函数并不是一个严肃的假设,尽管以优化的方式实现这个函数并不是一个 super 困难的任务(意味着实际上只向服务器发送我们之前没有计算过的路由等)。 但是这只是逻辑,不是应用程序的状态,因此,只要您保留存储和 reducer 定义的“契约”,您就可以自由地实现随心所欲。

希望这对您有帮助。

关于redux reducer vs Action ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37746358/

相关文章:

javascript - 我保证链接正确吗?

javascript - 在 React/Redux 中使用 Object.assign 或 Spread 运算符?这是更好的做法

reactjs - mapStateToProps 不提供状态数据

redux-thunk - 如何解决 "Actions must be plain objects. Use custom middleware for async actions.]"?

javascript - Async/Await 似乎在类方法和函数表达式中有不同的行为(React Hooks,Redux-Thunk)

javascript - ReactJS,Redux : How do I return an array of items in my STATE?

reactjs - 处理 axios React-Redux 应用程序中的 401 未经授权错误

Redux - 服务连接等副作用的时间旅行

javascript - 非 ui 应用程序的 Redux 架构

reactjs - React Redux Connect DefaultRootState 类型