本系列文以製作專案為主軸,紀錄小弟學習React以及GrahQL的過程。主要是記下重點步驟以及我覺得需要記憶的部分,有覺得不明確的地方還請留言多多指教。
有了可拖曳的物件後,接著製作可被拖放的目標。
跟拖曳時一樣,使用React DnD的 useDrop這個hook制定拖放物件。
這邊先製作把Todo拖放到Todo上的動作,在Todo中加上useDrop:
//Todo.jsx
export default function Todo({ name, listId, todoId, updateEditState }) {
//...
const [, drop] = useDrop({
accept: ItemTypes.TODO,
});
//...
}
useDrop必須設定accept屬性,指定哪一種type的拖曳物件能夠觸發這個拖放區。
這邊跟上一篇useDrag時設定的item type一樣是ItemTypes.TODO,就能確保觸發拖放效果。
想要在拖放後觸發效果,要在useDrop中設定drop屬性:
const [, drop] = useDrop({
accept: ItemTypes.TODO,
drop: (item) => { //制定拖放後的動作
console.log("Drop on todo", item);
},
});
drop會在物件收到指定type的拖放後觸發,而這裡可以取得拖曳物件的item屬性,就是上一篇在useDrag中設定的:
const [ , drag] = useDrag({
item: { listId, todoId, type: ItemTypes.TODO }
});
在item中我們提供了被拖曳物件的 listId跟 todoId,這在之後要替換Todo的位置的時候需要用到,目前只是印在console中。
確定有拖曳拖放的效果了!
不過拖放後畫面還是沒變化,因為就像上一篇說的,State沒變化,畫面也不會變。
所以再來要在drop後進行state的變動。
首先速速在slilce建好移動todo的reducer,在提供給Todo:
//todoSlice.js
const todosSlice = createSlice({
name: "todos",
initialState: dummyData,
reducers: {
//...
moveTodo(state, action) {
const { orgListId, orgTodoId, endListId, endTodoId } = action.payload;
const todo = state[orgListId].todos.splice(orgTodoId, 1);
state[endListId].todos.splice(endTodoId, 0, todo[0]);
},
}
// containers/Todo.js
//...
import { moveTodo } from "../reducers/todosSlice";
const mapDispatchToProps = { updateEditState, moveTodo };
export default connect(null, mapDispatchToProps)(Todo);
useDrag裡的item要把變數改名,免得drop的時候衝突。
// Todo.jsx
const [{ isDragging }, drag] = useDrag({
item: {
orgListId: listId, //變數改名
orgTodoId: todoId, //變數改名
type: ItemTypes.TODO,
},
}
接著在useDrop中就能執行更改位置的動作了
// Todo
const [, drop] = useDrop({
accept: ItemTypes.TODO,
drop: (item) => {
const { orgListId, orgTodoId } = item;
//將拖放目標的 listId等變數也改名後提供給moveTodo
moveTodo({ orgListId, orgTodoId, endListId: listId, endTodoId: todoId });
},
});
而當drop中的moveTodo被執行後,畫面也會更新: