上一篇文章我們定義好各種更新資料的 action 物件,這些物件會在呼叫 dispatch 函式傳入 reducer 函式,並且根據 type 屬性以及目前的 state 來決定如何更新資料,所以一個 reducer 大概會長這樣:
function reducer(state, action) {
switch (action.type) {
case 'ACTION_1':
// 更新邏輯
// return newState;
case 'ACTION_2':
// 更新邏輯
// return newState;
default:
return state;
}
}
依照上一篇文章定義好的各種 action type 都有一個對應的處理方式。
function reducer() {
switch (action.type) {
// 編輯標題
case "CHANGE_TITLE": {
const { title } = action.payload;
return {
...state,
title
};
}
// 新增看板
case "ADD_BOARD": {
const boardId = shortid.generate();
const { boardName } = action.payload;
return {
...state,
boards: {
ids: [...state.boards.ids, boardId],
byId: {
...state.boards.byId,
[boardId]: {
name: boardName,
cardIds: []
}
}
}
};
}
// 修改看板名稱
case "CHANGE_BOARD_NAME": {
const { boardId, boardName } = action.payload;
return {
...state,
boards: {
...state.boards,
byId: {
...state.boards.byId,
[boardId]: {
...state.boards.byId[boardId],
name: boardName
}
}
}
};
}
// 移動看板
case "MOVE_BOARD": {
const { draggingBoardId, targetBoardIndex } = action.payload;
const newBoardsIds = [...state.boards.ids];
const sourceBoardIndex = state.boards.ids.findIndex(
boardId => boardId === draggingBoardId
);
newBoardsIds.splice(sourceBoardIndex, 1);
newBoardsIds.splice(targetBoardIndex, 0, draggingBoardId);
return {
...state,
boards: {
...state.boards,
ids: newBoardsIds
}
};
}
// 刪除看板
case "REMOVE_BOARD": {
const { boardId } = action.payload;
const newBoardsIds = state.boards.ids.filter(id => id !== boardId);
const newBoardsById = { ...state.boards.byId };
delete newBoardsById[boardId];
const newCardsById = { ...state.cards.byId };
state.boards.byId[boardId].cardIds.forEach(cardId => {
delete newCardsById[cardId];
});
return {
...state,
boards: {
ids: newBoardsIds,
byId: newBoardsById
},
cards: {
byId: newCardsById
}
};
}
// 新增卡片
case "ADD_CARD": {
const cardId = shortid.generate();
const { boardId, cardValue } = action.payload;
return {
...state,
boards: {
...state.boards,
byId: {
...state.boards.byId,
[boardId]: {
...state.boards.byId[boardId],
cardIds: [...state.boards.byId[boardId].cardIds, cardId]
}
}
},
cards: {
byId: {
...state.cards.byId,
[cardId]: cardValue
}
}
};
}
// 修改卡片內容
case "CHANGE_CARD_VALUE": {
const { cardId, cardValue } = action.payload;
return {
...state,
cards: {
byId: {
...state.cards.byId,
[cardId]: cardValue
}
}
};
}
// 移動卡片
case "MOVE_CARD": {
const { draggingCardId, targetBoardId, targetCardIndex } = action.payload;
const sourceBoardId = Object.keys(state.boards.byId).find(boardId => {
return state.boards.byId[boardId].cardIds.find(
cardId => cardId === draggingCardId
);
});
const sourceBoardCardIds = [...state.boards.byId[sourceBoardId].cardIds];
const targetBoardCardIds =
sourceBoardId === targetBoardId
? sourceBoardCardIds
: [...state.boards.byId[targetBoardId].cardIds];
const sourceCardIndex = sourceBoardCardIds.findIndex(
cardId => cardId === draggingCardId
);
sourceBoardCardIds.splice(sourceCardIndex, 1);
targetBoardCardIds.splice(targetCardIndex, 0, draggingCardId);
return {
...state,
boards: {
...state.boards,
byId: {
...state.boards.byId,
[sourceBoardId]: {
...state.boards.byId[sourceBoardId],
cardIds: sourceBoardCardIds
},
[targetBoardId]: {
...state.boards.byId[targetBoardId],
cardIds: targetBoardCardIds
}
}
}
};
}
// 刪除卡片
case "REMOVE_CARD": {
const { draggingCardId } = action.payload;
const sourceBoardId = Object.keys(state.boards.byId).find(boardId => {
return state.boards.byId[boardId].cardIds.find(
cardId => cardId === draggingCardId
);
});
const sourceBoardCardIds = [...state.boards.byId[sourceBoardId].cardIds];
const sourceCardIndex = sourceBoardCardIds.findIndex(
cardId => cardId === draggingCardId
);
sourceBoardCardIds.splice(sourceCardIndex, 1);
const newCardsById = { ...state.cards.byId };
delete newCardsById[draggingCardId];
return {
...state,
boards: {
...state.boards,
byId: {
...state.boards.byId,
[sourceBoardId]: {
...state.boards.byId[sourceBoardId],
cardIds: sourceBoardCardIds
}
}
},
cards: {
byId: newCardsById
}
};
}
default:
return state;
}
}
如果完全沒有對應的 action type,那就返回原本的 state,另外在新增看板或是新增卡片時,我們使用 shortid 套件來幫看板或卡片建立不重複的 id,方便用來查找看板或卡片。
開始建立元件,從根元件開始!