改进redux减速器

时间:2016-03-23 19:40:21

标签: redux

对于下面的Redux reducer代码(主要关注UPDATE_TASK动作和updateTask reducer函数),我在我的状态对象上保留一个project。这个project有多个milestones,而这又有多个tasks

当我更新给定任务时,我正在触发UPDATE_TASK操作。然后,它将执行PUT请求,并接收task的更新版本作为有效负载。

接下来,我遍历我所在状态的milestones对象的project。如果它与任务milestone_id匹配,那么我继续遍历该里程碑的所有tasks,构建一个包含所有先前任务的集合,替换我从中获取的任务。响应。

这是使用Redux构建修改状态的最佳方法吗?另外,是否建议像我一样提取非平凡状态更新的函数?我的代码可以改进什么(风格或任何我不知道的ES6技巧)?

import { FETCH_PROJECT } from '../actions/index';
import { FETCH_PROJECTS } from '../actions/index';
import { FETCH_MILESTONES } from '../actions/index';
import { FETCH_TASKS } from '../actions/index';
import { UPDATE_TASK } from '../actions/index';

const INITIAL_STATE = { all: [], project: null, milestones: [] };

// injects a collection of tasks on the milestone that
// matches the id we're using to fetch
function updateTasks(state, action) {
  const milestones = state.project.milestones.map((milestone) => {
    if (milestone.id == action.meta.id) {
      return { ...milestone, tasks: action.payload.data.tasks }
    }
    return milestone;
  });
  const project = { ...state.project, milestones };

  return { ...state, project };
}

// updates a single task on the proper milestone
function updateTask(state, action) {
  const { task } = action.payload.data;
  const milestones = state.project.milestones.map((milestone) => {
    if (milestone.id == task.milestone_id) {
      const tasks = milestone.tasks.map((milestoneTask) => {
        if (milestoneTask.id == task.id) {
          return task;
        }
        return milestoneTask;
      });

      return { ...milestone, tasks: tasks };
    }
    return milestone;
  });
  const project = { ...state.project, milestones };

  return { ...state, project };
}

export default function(state = INITIAL_STATE, action) {
  switch (action.type) {
    case FETCH_PROJECT:
      return { ...state, project: action.payload.data.project };

    case FETCH_PROJECTS:
      return { ...state, all: action.payload.data.projects };

    case FETCH_MILESTONES:
      return { ...state, milestones: action.payload.data.milestones };

    case FETCH_TASKS:
      return updateTasks(state, action);

    case UPDATE_TASK:
      return updateTask(state, action);
  }

  return state;
}

1 个答案:

答案 0 :(得分:3)

围绕您执行的操作类型构建缩减器。更好的方法是围绕状态包含的数据构建缩减器。

因此,请仔细研究您的初始状态:

const INITIAL_STATE = { all: [], project: null, milestones: [] };

您可以为每个人创建一个单独的减速器。这样的事情可行。

function projects(state={}, action) {
    case FETCH_PROJECTS:
        return action.payload.data.projects
    ...etc
}

function activeProject(state={}, action) {
    case FETCH_PROJECT:
        return action.payload.data.project
    case FETCH_MILESTONES:
        // add milestone to appropriate project
}

function milestones(state={}, action) {
    case FETCH_MILESTONES:
        // add milestone
    case FETCH_TASKS:
         // add task to appropriate milestone

}

function tasks(state={}, action) {
    case FETCH_TASKS:
        // update appropriate task
}

之后您可以使用combineReducers组合所有这些缩减器,或者自己组合它们。

要在构建日期方面获得一些帮助,请查看https://github.com/gaearon/normalizr。我们的想法是让您的数据尽可能平稳地表现在您的Reducer中。这样您就不需要嵌套的Reducer,从而避免了复杂性。

在您的示例中,每个里程碑都可以创建一个创建对象的任务列表:

{
   m1: { tasks: [t1,t2], ...}
   m2: { tasks: [t3], ...}
   m3: { tasks: [t4,t5], ...}
}

您的任务可以是将ID映射到其内容的对象,如:

{
   t1: {} //task 
   t2: {} //task 
   t3: {} //task 
   t4: {} //task 
   t5: {} //task 
}

对于项目和里程碑也是如此,以同样的方式将它们联系起来。