Notice
Recent Posts
Recent Comments
Link
«   2026/02   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
Archives
Today
Total
관리 메뉴

사고쳤어요

[React / ts] Task App 만들기 - ③ ActionButton 만들기 본문

웹 풀스택

[React / ts] Task App 만들기 - ③ ActionButton 만들기

kevinmj12 2025. 4. 15. 19:25


"새로운 일 등록" 버튼과 "새로운 리스트 등록" 버튼을 눌렀을 때 각 기능을 수행할 수 있도록 구현해보자.

// ActionButton.tsx

import React, { useState } from "react";
import { IoIosAdd } from "react-icons/io";
import DropDownForm from "../DropDownForm/DropDownForm";
import { listButton, taskButton } from "./ActionButton.css";

type TActionButtonProps = {
  boardId: string;
  listId: string;
  list?: boolean;
};

const ActionButton: React.FC<TActionButtonProps> = ({
  boardId,
  listId,
  list,
}) => {
  const [isFormOpen, setIsFormOpen] = useState(false);
  const buttonText = list ? "새로운 리스트 등록" : "새로운 일 등록";

  return isFormOpen ? (
    <DropDownForm
      setIsFormOpen={setIsFormOpen}
      list={list ? true : false}
      boardId={boardId}
      listId={listId}
    />
  ) : (
    <div
      className={list ? listButton : taskButton}
      onClick={() => setIsFormOpen(true)}
    >
      <IoIosAdd />
      <p>{buttonText}</p>
    </div>
  );
};

export default ActionButton;

 

ActionButton은 "새로운 리스트 등록", "새로운 일 등록" 두 가지의 경우를 모두 처리한다.

따라서 list를 props로 전달받아 이가 true일 때를 리스트, false일 때는 일을 추가한다.

 

ActionButton은 기본적으로 "새로운 ... 등록"을 보여주고 있다가, 만약 이를 클릭할 경우

텍스트를 입력할 수 있는 input과 추가 버튼이 포함된 DropDownForm을 보여주도록 하였다.

 

// DropDownForm.tsx

import React, { ChangeEvent, useState } from "react";
import { FiX } from "react-icons/fi";
import { useTypedDispatch } from "../../hooks/redux";
import { v4 } from "uuid";
import { addList, addTask } from "../../store/slices/boardsSlice";
import { addLog } from "../../store/slices/loggerSlice";
import {
  button,
  buttons,
  input,
  listForm,
  taskForm,
  close,
} from "./DropDownForm.css";

type TDropDownFormProps = {
  boardId: string;
  listId: string;
  setIsFormOpen: React.Dispatch<React.SetStateAction<boolean>>;
  list?: boolean;
};

const DropDownForm: React.FC<TDropDownFormProps> = ({
  boardId,
  listId,
  setIsFormOpen,
  list,
}) => {
  const dispatch = useTypedDispatch();

  const [text, setText] = useState("");
  const handleTextChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
    setText(e.target.value);
  };

  const formPlaceHolder = list
    ? "리스트의 제목을 입력하세요"
    : "일의 제목을 입력하세요";

  const buttonTitle = list ? "리스트 추가하기" : "일 추가하기";
  const handleButtonClick = () => {
    if (text) {
      if (list) {
        dispatch(
          addList({
            boardId,
            list: { listId: v4(), listName: text, tasks: [] },
          })
        );
        dispatch(
          addLog({
            logId: v4(),
            logMessage: `리스트 생성하기: ${text}`,
            logAuthor: "User",
            logTimestamp: Date.now().toString(),
          })
        );
      } else {
        dispatch(
          addTask({
            boardId,
            listId,
            task: {
              taskId: v4(),
              taskName: text,
              taskDescription: "",
              taskOwner: "User",
            },
          })
        );
        dispatch(
          addLog({
            logId: v4(),
            logMessage: `일 생성하기 ${text}`,
            logAuthor: "User",
            logTimestamp: Date.now().toString(),
          })
        );
      }
    }
  };

  return (
    <div className={list ? listForm : taskForm}>
      <textarea
        className={input}
        autoFocus
        placeholder={formPlaceHolder}
        onChange={(e) => {
          handleTextChange(e);
        }}
        onBlur={() => setIsFormOpen(false)}
      />
      <div className={buttons}>
        <button className={button} onMouseDown={handleButtonClick}>
          {buttonTitle}
        </button>
        <FiX className={close} />
      </div>
    </div>
  );
};

export default DropDownForm;

 

본격적으로 list 추가하기 기능과 task 추가하기 기능을 구현하는 단계이다.

dispatch를 활용하여 addList와 addTask를 받아와 실행해주면 된다.

 

// boardsSlice.ts

addList: (state, { payload }: PayloadAction<TAddListAction>) => {
  state.boardArray.map((board) =>
    board.boardId === payload.boardId
      ? { ...board, lists: board.lists.push(payload.list) }
      : board
  );
},
addTask: (state, { payload }: PayloadAction<TAddTaskAction>) => {
  state.boardArray.map((board) =>
    board.boardId === payload.boardId
      ? {
          ...board,
          list: board.lists.map((list) =>
            list.listId === payload.listId
              ? { ...list, tasks: list.tasks.push(payload.task) }
              : list
          ),
        }
      : board
  );
},

 

addList와 addTask를 처리하는 부분이다.

board -> list -> task의 계층 구조로 이루어져 있다는 것을 생각하면 어렵지 않게 구현할 수 있다.