在 Redux Reducer 中设置项目以完成 2 个级别
Set item to complete 2 levels deep in Redux Reducer
几个小时以来一直在努力解决这个问题...
如何在 Task 对象内的 Notes 中设置完成切换?
我接近这个了吗?
减速器:
let taskReducer = function(tasks = [], action) {
case 'COMPLETE_NOTE':
return tasks.map((task) => {
if(action.taskId !== task.id) {
return task;
} else if(action.taskId === task.id) {
const { notes } = task;
notes.map((note) => {
return note.id === action.noteId ?
Object.assign({}, note, {note: {completed: !note.completed}}): note
})
}
})
default:
return tasks;
}
}
操作:
let actions = {
completeNote: (taskId, noteId) => {
return {
type: 'COMPLETE_NOTE',
taskId: taskId,
noteId: noteId,
}
}
}
客户:
let initialState = {
tasks: [{
id: 1,
title: 'do this',
completed: false,
notes: [{
id: 0,
title: 'note1',
completed: false
}]
}]
}
看来您已经找到了让它发挥作用的方法。只要每个注释都与一个任务相关联并且此代码不会造成性能瓶颈,我可能会坚持使用您已经制定的解决方案。如果您愿意,我可以详细说明这些潜在问题中的任何一个,但我认为您的方法对于简单的待办事项应用程序来说效果很好。
编辑
阅读您的评论后,我现在明白您正在尝试解决错误,而不仅仅是询问是否存在 "better way"。抱歉阅读太快了。无论如何,要解决此问题,您需要 return 在 elseif
块中执行任务。例如:
else if(action.taskId === task.id) {
const { notes } = task;
return {
...task,
notes: notes.map((note) => {
return note.id !== action.noteId ? note : {
...note,
completed: !note.completed
};
})
};
}
// Without using spread operator
else if(action.taskId === task.id) {
const { notes } = task;
return Object.assign({}, task, {
notes: notes.map((note) => {
return note.id !== action.noteId ? note : Object.assign({}, note, {
completed: !note.completed
})
})
});
}
你做错了。
首先,我建议您创建一个对象,而不是一组任务,其中的待办事项由它们的 ID 映射。笔记也一样。所以你的状态对象看起来像:
tasks: {
"uniqueid1": {
title: "some task",
completed: false,
notes: {
"noteid1": {
title: "some note",
completed: false
}
}
},
"uniqueid2": {
...
},
...
}
然后为todo和note的每个部分创建一个reducer,并使用combineReducers
函数创建一个task对象。所以在你的代码中你会有这样的东西:
const task = combineReducers({
title: taskTitle, // taskTitle is a reducer
completed: taskCompleted, //taskCompleted is a reducer
notes
});
// example implementation of the notes reducer:
const notes = (state = {}, action) => {
switch(action.type) {
case 'CHANGE_NOTE_TITLE':
case 'COMPLETE_NOTE':
return {
...state,
[action.noteId]: note(state[action.noteId], action)
};
default:
return state;
}
}
const note = (state, action) => {
switch(action.type) {
case 'COMPLETE_NOTE':
return {
...state,
completed: true
};
case 'CHANGE_NOTE_TITLE':
return {
...state,
title: action.newTitle
};
default:
return state;
}
}
// note that you could split *note* into *title* and *completed* reducers
// and use the combineReducers function again
Redux 的一个基本思想是你有很多 reducer,每个 reducer 只处理整个状态的一小部分。这很好地分离了关注点并使代码更易于维护。
我建议你 watch Dan Abramov's (the author of Redux) free course Idiomatic Redux 他谈论所有这些东西的地方。
几个小时以来一直在努力解决这个问题... 如何在 Task 对象内的 Notes 中设置完成切换?
我接近这个了吗?
减速器:
let taskReducer = function(tasks = [], action) {
case 'COMPLETE_NOTE':
return tasks.map((task) => {
if(action.taskId !== task.id) {
return task;
} else if(action.taskId === task.id) {
const { notes } = task;
notes.map((note) => {
return note.id === action.noteId ?
Object.assign({}, note, {note: {completed: !note.completed}}): note
})
}
})
default:
return tasks;
}
}
操作:
let actions = {
completeNote: (taskId, noteId) => {
return {
type: 'COMPLETE_NOTE',
taskId: taskId,
noteId: noteId,
}
}
}
客户:
let initialState = {
tasks: [{
id: 1,
title: 'do this',
completed: false,
notes: [{
id: 0,
title: 'note1',
completed: false
}]
}]
}
看来您已经找到了让它发挥作用的方法。只要每个注释都与一个任务相关联并且此代码不会造成性能瓶颈,我可能会坚持使用您已经制定的解决方案。如果您愿意,我可以详细说明这些潜在问题中的任何一个,但我认为您的方法对于简单的待办事项应用程序来说效果很好。
编辑
阅读您的评论后,我现在明白您正在尝试解决错误,而不仅仅是询问是否存在 "better way"。抱歉阅读太快了。无论如何,要解决此问题,您需要 return 在 elseif
块中执行任务。例如:
else if(action.taskId === task.id) {
const { notes } = task;
return {
...task,
notes: notes.map((note) => {
return note.id !== action.noteId ? note : {
...note,
completed: !note.completed
};
})
};
}
// Without using spread operator
else if(action.taskId === task.id) {
const { notes } = task;
return Object.assign({}, task, {
notes: notes.map((note) => {
return note.id !== action.noteId ? note : Object.assign({}, note, {
completed: !note.completed
})
})
});
}
你做错了。
首先,我建议您创建一个对象,而不是一组任务,其中的待办事项由它们的 ID 映射。笔记也一样。所以你的状态对象看起来像:
tasks: {
"uniqueid1": {
title: "some task",
completed: false,
notes: {
"noteid1": {
title: "some note",
completed: false
}
}
},
"uniqueid2": {
...
},
...
}
然后为todo和note的每个部分创建一个reducer,并使用combineReducers
函数创建一个task对象。所以在你的代码中你会有这样的东西:
const task = combineReducers({
title: taskTitle, // taskTitle is a reducer
completed: taskCompleted, //taskCompleted is a reducer
notes
});
// example implementation of the notes reducer:
const notes = (state = {}, action) => {
switch(action.type) {
case 'CHANGE_NOTE_TITLE':
case 'COMPLETE_NOTE':
return {
...state,
[action.noteId]: note(state[action.noteId], action)
};
default:
return state;
}
}
const note = (state, action) => {
switch(action.type) {
case 'COMPLETE_NOTE':
return {
...state,
completed: true
};
case 'CHANGE_NOTE_TITLE':
return {
...state,
title: action.newTitle
};
default:
return state;
}
}
// note that you could split *note* into *title* and *completed* reducers
// and use the combineReducers function again
Redux 的一个基本思想是你有很多 reducer,每个 reducer 只处理整个状态的一小部分。这很好地分离了关注点并使代码更易于维护。
我建议你 watch Dan Abramov's (the author of Redux) free course Idiomatic Redux 他谈论所有这些东西的地方。