ReactJS/개념정리

[REACT] todolist 만들기

xowoony 2023. 4. 18. 23:27

학습일 : 2023. 04. 18


이제 todolist를 본격적으로 만들어보도록 하자.


 

타입스크립트에게 toDo가 어떻게 생겼는지 알려주기 위한 인터페이스를 먼저 작성한다.
toDoState는 toDo들의 배열이라는 것을 알려주도록 하겠다.
category는 'DONE', 'DOING', 'TODO'만 받을 수 있다고 알려주도록 한다.
이제 ToDo를 만들면 모든 string이 아닌, 명시된 3개 중 하나의 string만을 가져야 한다.

interface IToDo {
  text: string;
  // id도 적어줌
  id: number;
  category: "TODO" | "DOING" | "DONE";
}

 

 

이제 atom의 type이 ToDo의 배열임을 알려주도록 하자.
atom<IToDo[]> 를 작성해준다.

const toDoState = atom<IToDo[]>({
  key: "toDo",
  default: [],
});

 

 

이제 타입스크립트는 toDos가 IToDo 객체로 이뤄진 배열임을 알게되었다.

  const [toDos, setToDos] = useRecoilState(toDoState);

 

이제 하고자 하는 것은 폼이 제출되고 데이터가 모두 유효하다면,
  state(상태)를 바꿀 것이다.

 

 

 

 

 

  여기서 state를 바꿔줄 것이다.

 const handleValid = ({ toDo }: IForm) => {
    setToDos((oldToDos) => [
      // id를 써줌
      { text: toDo, category: "TODO", id: Date.now() },
      ...oldToDos,
    ]);
    setValue("toDo", "");
  };


    setToDos 함수는 두개의 동작을 할 수 있다.
    1. state를 직접적으로 설정해 줄 수도 있고,

2. 다른 함수를 받을 수도 있다.


    () 안에 함수를 쓴다면, 함수의 리턴값이 새로운 state가 될 것이다.
    이전의 state를 oldToDos로 받아서 배열을 반환해줄 것이다.
    그렇게 되면 이 배열은 oldToDos의 모든 요소를 가지게 된다.
    보다시피 oldToDos는 배열이다.


    setToDos((oldToDos) => [oldToDos]);

이런 방식으로 하면 배열안에 배열이 들어가버린 꼴이 되므로 안되고
    내가 원하는 건 oldToDo의 요소들이 들어있는 배열을 반환해야 하므로
    setToDos((oldToDos) => [...oldToDos]); 로 써준다.

이것은 배열안의 요소를 반환하게 된다.


    지금까지를 보면 단순히 oldToDo를 받아서 oldToDo를 반환한다.
    내가 해야 할 것은 새로운 ToDo를 넣어주는 것이다.


    따라서 안에 객체를 만들고
    우리의 데이터는 data.toDo에 있고,

data는 react-hook-form에서 넘어온다.
    그리고 이 data.toDo는 밑에 있는 input에서 온 것이다.
    {text:toDo} 를 써주면서 이제 text를 사용한다고 말해 줄 것이다.
    새로운 ToDo의 text는 toDo로부터 오는 것이다.
    그리고 카테고리도 작성해준다.
    모든 ToDo를 TODO로부터 시작할 것이기 때문에 TODO로 적어준다.

 

 

 

전체 코드

<ToDoList.tsx>

import { useForm } from "react-hook-form";
import {
  atom,
  useRecoilState,
  useRecoilValue,
  useSetRecoilState,
} from "recoil";


const toDoState = atom<IToDo[]>({
  key: "toDo",
  default: [],
});


interface IToDo {
  text: string;
  id: number;
  category: "TODO" | "DOING" | "DONE";
}

interface IForm {
  toDo: string;
}

function ToDoList() {
  const [toDos, setToDos] = useRecoilState(toDoState);
  const { register, handleSubmit, setValue } = useForm<IForm>();
  const handleValid = ({ toDo }: IForm) => {
    setToDos((oldToDos) => [
      { text: toDo, category: "TODO", id: Date.now() },
      ...oldToDos,
    ]);
    setValue("toDo", "");
  };

  console.log(toDos);

  return (
    <div>
      <h1>Thorn To Do</h1>
      <hr />
      <form onSubmit={handleSubmit(handleValid)}>
        <input
          {...register("toDo", {
            required: "please write a to do",
          })}
          placeholder="오늘 해야할 일을 입력하세요"
        />
        <button>add</button>
      </form>
      <ul>
         {toDos.map(toDo => <li key={toDo.id}>{toDo.text}</li>)}
      </ul>
    </div>
  );
}

export default ToDoList;

 

 

 

결과

 

 

다음 글에 계속...:>