칸반 스타일의 할 일 앱 만들기
8403 단어 htmljavascriptcssreact
이 게시물은 무엇에 관한 것입니까?
이 기사에서는 Kanban 스타일의 todo 앱을 구축하는 방법을 살펴보겠습니다. 각 할일 작업에는 시작되지 않음, 진행 중, 완료의 3가지 상태가 있습니다. 새 할 일이 추가되자마자 기본 상태는 시작되지 않음이고 사용자는 상태 사이를 드래그할 수 있습니다. 이 앱은 최소한의 기능 구현보다는 스타일링에 중점을 둡니다.
여기에서 앱을 확인하세요: Kanban style todo App
콘텐츠
각각에 대해 자세히 살펴보고 구현 방법을 살펴보겠습니다.
설계
새 할 일 추가
Todo는 입력 영역을 사용하여 추가되며 기본 상태는 시작되지 않음입니다.
// Component
const TodoInput = ({ onTodoAdd }) => {
const [todoInput, setTodoInput] = useState("");
const onAdd = (e) => {
e.preventDefault();
onTodoAdd(todoInput);
setTodoInput("");
};
return (
<form className="todo-input">
<input
placeholder="Add Todo entry"
value={todoInput}
onChange={(e) => setTodoInput(e.target.value)}
/>
<button onClick={onAdd} type="submit">
Add
</button>
</form>
);
};
// onTodoAdd Prop implementation
const onTodoAdd = (todoText) => {
setTodos((_t) => {
return [
..._t,
{
id: uuidv4(), // Generate unique id
value: todoText,
state: TODO_STATE.NOT_STARTED,
},
];
});
};
할 일 상태 변경
할일의 상태에 따라 할일을 보관할 많은 상태 컨테이너가 필요합니다. 따라서 이 경우에는 3개의 컨테이너[시작되지 않음, 진행 중, 완료]가 있습니다.
각 컨테이너는 드롭할 항목의 드롭 영역 역할을 합니다.
각 작업 항목은 끌어서 놓을 수 있는 항목으로 작동하며 사용 가능한 모든 놓기 영역에 놓을 수 있습니다.
드롭 영역: 시작되지 않음, 진행 중, 완료, 삭제.
끌어서 놓기 기능을 구현하기 위해 사용할 것입니다React DnD.
export const TODO_STATE = {
NOT_STARTED: "Not started",
IN_PROGRESS: "In progress",
DONE: "Done",
};
const TodoContent = ({ todos, onTodoDrag, onTodoDelete }) => {
const notStartedTodos = getTodosBasedOnState(todos, TODO_STATE.NOT_STARTED);
const inProgressTodos = getTodosBasedOnState(todos, TODO_STATE.IN_PROGRESS);
const doneTodos = getTodosBasedOnState(todos, TODO_STATE.DONE);
const [isDragActive, setIsDragActive] = useState(false);
const onDragActive = (dragActive) => {
setIsDragActive(dragActive);
};
return (
<DndProvider backend={HTML5Backend}>
<div className="todo-content">
<DraggableItemContainer
title="Not Started"
todos={notStartedTodos}
onTodoDrag={onTodoDrag}
state={TODO_STATE.NOT_STARTED}
onDragActive={onDragActive}
onTodoDelete={onTodoDelete}
/>
<DraggableItemContainer
title="In Progress"
todos={inProgressTodos}
onTodoDrag={onTodoDrag}
state={TODO_STATE.IN_PROGRESS}
onDragActive={onDragActive}
onTodoDelete={onTodoDelete}
/>
<DraggableItemContainer
title="Done"
todos={doneTodos}
onTodoDrag={onTodoDrag}
state={TODO_STATE.DONE}
onDragActive={onDragActive}
onTodoDelete={onTodoDelete}
/>
</div>
{isDragActive && (
<div className="delete-drag-container">
<DeleteDragItemBox />
</div>
)}
</DndProvider>
);
};
드래그 가능한 컨테이너
const DraggableItemContainer = ({
title = "",
todos = [],
onTodoDrag,
state,
onDragActive,
onTodoDelete,
}) => {
const [{ canDrop, isOver }, drop] = useDrop(() => ({
accept: ITEM_TYPES.TODO,
drop: () => ({ state }),
collect: (monitor) => ({
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
}),
}));
const isActive = canDrop && isOver;
const style = {
border: isActive ? "3px dashed black" : "1px solid black",
};
return (
<div className="draggable-item-container" ref={drop} style={style}>
<h4 className="title">
{title} - [{todos.length}]
</h4>
<div className="content">
{todos.map((t) => {
return (
<DraggableItem
key={t.id}
todo={t}
onTodoDrag={onTodoDrag}
onDragActive={onDragActive}
onTodoDelete={onTodoDelete}
/>
);
})}
</div>
</div>
);
};
드래그 가능한 항목 a.k.a Todo 항목
const DraggableItem = ({ todo, onTodoDrag, onDragActive, onTodoDelete }) => {
const [{ isDragging }, drag] = useDrag(() => ({
type: ITEM_TYPES.TODO,
item: { todo },
end: (item, monitor) => {
const dropResult = monitor.getDropResult();
if (item && dropResult) {
if (!dropResult.delete) {
onTodoDrag(item.todo.id, dropResult.state);
} else {
onTodoDelete(item.todo.id);
}
onDragActive(false);
}
},
collect: (monitor) => ({
isDragging: monitor.isDragging(),
handlerId: monitor.getHandlerId(),
}),
isDragging: (monitor) => {
if (todo.id === monitor.getItem().todo.id) {
onDragActive(true);
}
},
}));
const opacity = isDragging ? 0.4 : 1;
const textDecoration =
todo.state === TODO_STATE.DONE ? "line-through" : "none";
let backgroundColor = "";
switch (todo.state) {
case TODO_STATE.NOT_STARTED: {
backgroundColor = "lightcoral";
break;
}
case TODO_STATE.IN_PROGRESS: {
backgroundColor = "lightyellow";
break;
}
case TODO_STATE.DONE: {
backgroundColor = "lightgreen";
break;
}
default: {
backgroundColor = "white";
break;
}
}
return (
<div
className="draggable-item"
ref={drag}
style={{ opacity, textDecoration, backgroundColor }}
>
{todo.value}
</div>
);
};
이벤트 : onTodoDrag
const onTodoDrag = (id, state) => {
setTodos((_t) =>
_t.map((t) => {
if (t.id === id) {
return { ...t, state };
}
return t;
})
);
};
할 일 삭제
드롭존 삭제
const DeleteDragItemBox = () => {
const [{ canDrop, isOver }, drop] = useDrop(() => ({
accept: ITEM_TYPES.TODO,
drop: () => ({ delete: true }),
collect: (monitor) => ({
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
}),
}));
const isActive = canDrop && isOver;
const style = {
border: isActive ? "3px dashed black" : "none",
};
return (
<div className="delete-drag-box" style={style} ref={drop}>
<DeleteIcon width={'4rem'}/>
</div>
);
};
const onTodoDelete = (id) => {
setTodos((_t) => _t.filter((t) => t.id !== id));
};
결론
이 게임을 구현하면 원하는 논리를 구현하기 위해 React에서 상태 및 부작용을 사용하는 방법을 배울 수 있습니다. 이 앱은 실제 응용 프로그램에 사용되는 새로운 구성 요소 학습의 일부로 만들어졌습니다.
안전을 유지하고 다른 사람에게 손을 빌려주세요 :)
Reference
이 문제에 관하여(칸반 스타일의 할 일 앱 만들기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/vigneshiyergithub/building-a-kanban-style-todo-app-1ohi텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)