对于下面的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;
}
答案 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
}
对于项目和里程碑也是如此,以同样的方式将它们联系起来。