[스터디] #8 (투두리스트) - Recoil

ch9eri·2022년 10월 6일
0

🌐 useRecoilState(state)

형식은 기존의 useState와 유사함

const [value, modFn] = useRecoilState(toDoState);

첫번째 항목 : value (never(빈) 타입의 배열)
두번째 항목 : value를 변경하기 위한 함수

💡 useRecoilValue: state값을 리턴
💡 useSetRecoilState: setter 함수를 리턴
💡 useRecoilState: state, setter 함수를 모두 리턴

const toDoState = atom<IToDo[]>({
  key: "toDo",
  default: [],
});
interface IToDo {
  text: string;
  id: number;
  category: "TO_DO" | "DOING" | "DONE";
}

-> ToDo를 만들 때 "TO_DO" | "DOING" | "DONE" 이 3개의 string 중 하나만 가져야함

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

toDosIToDo 객체로 이루어진 배열

❌) 그냥 냅다 toDos.push() → 이러면 리렌더링이 안됨

❌) setToDos(oldToDos ⇒ [oldToDos]) → 배열 안에 배열을 담아서 리턴

✅) setToDos(oldToDos ⇒ [...oldToDos]) → 배열 안의 요소 를 리턴

🖥 저장한 toDos 배열 화면에 출력하기

<ul>
        {toDos.map((toDo) => (
          <li key={toDo.id}>{toDo.text}</li>
        ))}
</ul>

🛠 Refactoring - 컴포넌트 분리하기

<ToDoList> 컴포넌트를

<ToDoList> <CreateToDo> <ToDo> 로 나누었다

(이건 그냥 분리한 거니까 생략 …)

{toDos.map((toDo) => (
          <ToDo text={toDo.text} category={toDo.category} id={toDo.id} />
))}

props를 넘겨줄 때 … 이렇게 긴 코드를

{toDos.map((toDo) => (
          <ToDo {...toDo} />
))}

toDos 리스트의 toDo가 <ToDo> 컴포넌트에서 필요한 props와 같은 모양 (같은 IToDo interface)이기 때문에

<ToDo key={toDo.id} {...toDo} />

이렇게 짧게 줄일 수 있다

➕) map함수 내에서 item을 render할 때 key 필요함

{toDos.map((toDo) => (
	<ToDo key={toDo.id} {...toDo} />
))}

➕) : 해당 배열 안의 모든 원소를 풀어놓기

const food = [”pizza”, “mango”, “kimchi”, “kimbab”]
const front = [”pizza”]
const back = [”kimchi”, “kimbab”]
const finalpart = […front, “감”, …back”]

💡 event를 통해서 button의 name 가져오기

<button name="DOING" onClick={onClick}>
	Doing
</button>
const {
	currentTarget: { name },
} = event;

📌 Selector

atom의 output을 변형시키는 도구
Selector는 파생된 state의 일부를 나타낸다.
기존 state를 가져와서, 기존 state를 이용해 새로운 state를 만들어서 반환할 수 있다.
(기존 state를 이용만할 뿐 변형시키지 않는다)

🧩 filter

배열에서 조건에 맞지 않는 원소들을 제거한 배열을 return

toDos.filter((toDo) => toDo.category === "TO_DO")

-> category가 TO_DO인 원소들만 담은 배열을 return

💡 selector에서 값을 받아오기

export const toDoSelector = selector({
    key: "toDoSelector",
    get: ({ get }) => {
      const toDos = get(toDoState);
      return [
        toDos.filter((toDo) => toDo.category === "TO_DO"),
        toDos.filter((toDo) => toDo.category === "DOING"),
        toDos.filter((toDo) => toDo.category === "DONE"),
      ];
    },
  });
const [toDo, doing, done] = useRecoilValue(toDoSelector);

배열 안에 순서대로 이름을 지정

<h2>To Do</h2>
       <ul>
         {toDo.map((toDo) => (
           <ToDo key={toDo.id} {...toDo} />
         ))}
       </ul>
       <hr />
       <h2>Doing</h2>
       <ul>
         {doing.map((toDo) => (
           <ToDo key={toDo.id} {...toDo} />
         ))}
       </ul>
       <hr />
       <h2>Done</h2>
       <ul>
         {done.map((toDo) => (
           <ToDo key={toDo.id} {...toDo} />
         ))}
       </ul>

그럼 이렇게 간단하게 배열 속의 배열 가져오기 가능!

💡 원하는 카테고리의 리스트만 보이게 하기

export const categoryState = atom({
  key: 'category',
  default: 'TO_DO',
});
<select onInput={onInput}>
        <option value="TO_DO">To Do</option>
        <option value="DOING">Doing</option>
        <option value="DONE">Done</option>
</select>



이제 이 카테고리에 따라 나누기 위해

현재의 값과 값을 수정하는 함수가 필요함 → useRecoilState

const [category, setCategory] = useRecoilState(categoryState);
const toDos = useRecoilValue(toDoSelector);
export const toDoSelector = selector({
  key: 'toDoSelector',
  get: ({ get }) => {
    const toDos = get(toDoState);
    const category = get(categoryState);
    return toDos.filter((toDo) => toDo.category === category);
  },
});
{toDos?.map((toDo) => (
        <ToDo key={toDo.id} {...toDo} />
      ))}

category에 따라서 selector가 각각의 toDo 배열 반환

🔠 Enums

열거형으로 이름이 있는 상수들의 집합을 정의할 수 있다

const category = useRecoilValue(categoryState);
export const categoryState = atom<"TO_DO" | "DOING" | "DONE">({
  key: 'category',
  default: 'TO_DO',
});

-> typescript에게 categoryState가 "TO_DO" | "DOING" | "DONE" 셋 중 하나일 것이라고 알려주기

export enum Categories {
  'TO_DO' = 'TO_DO',
  'DOING' = 'DOING',
  'DONE' = 'DONE',
}
<option value={Categories.TO_DO}>To Do</option>
         <option value={Categories.DOING}>Doing</option>
         <option value={Categories.DONE}>Done</option>
      </select>

-> string 작성시 실수할 확률 줄어든다!

cf) 기존 코드

<select onInput={onInput}>
        <option value="TO_DO">To Do</option>
        <option value="DOING">Doing</option>
        <option value="DONE">Done</option>
</select>

✨ 투두리스트 제작 완료

지난주에 recoil없이 투두리스트를 제작해보았는데 props를 넘겨줄 때 엄청나게 헷갈렸던 경험이 있어서 recoil의 중요성이 더 크게 느껴졌다 ... 휴

profile
잘하자!

0개의 댓글