在 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 他谈论所有这些东西的地方。