iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 16
0
Modern Web

React + GraphQL 全端練習筆記系列 第 16

仿Trello - 用React DnD製作拖放(drop)功能

本系列文以製作專案為主軸,紀錄小弟學習React以及GrahQL的過程。主要是記下重點步驟以及我覺得需要記憶的部分,有覺得不明確的地方還請留言多多指教。

有了可拖曳的物件後,接著製作可被拖放的目標。

useDrop

跟拖曳時一樣,使用React DnD的 useDrop這個hook制定拖放物件。

這邊先製作把Todo拖放到Todo上的動作,在Todo中加上useDrop:

//Todo.jsx
export default function Todo({ name, listId, todoId, updateEditState }) {

  //...
  
  const [, drop] = useDrop({
    accept: ItemTypes.TODO,
  });
    
  //...
}

accept

useDrop必須設定accept屬性,指定哪一種type的拖曳物件能夠觸發這個拖放區。

這邊跟上一篇useDrag時設定的item type一樣是ItemTypes.TODO,就能確保觸發拖放效果。

drop

想要在拖放後觸發效果,要在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被執行後,畫面也會更新:

References:


上一篇
仿Trello - 用React DnD製作拖曳(drag)功能
下一篇
仿Trello - 客製化拖曳圖示
系列文
React + GraphQL 全端練習筆記30

尚未有邦友留言

立即登入留言