Recoil 사용기 - 2 (Normal)

soonrok·2022년 12월 21일
0

Recoil

목록 보기
2/2
post-thumbnail

지난 포스팅에서 Recoil의 간단한 개념 설명과 설치, 사용법에 대해 알아봤다.
이번에는 Recoil을 사용한 전역 상태 관리를 통해 공식 문서에 나와있는 TODO 애플리케이션을 만들어보자.

기능 정의

해당 TODO 애플리케이션은 다음의 기능을 포함하게 구현될 것이다.

  • todo 아이템 추가
  • todo 아이템 수정
  • todo 아이템 삭제
  • todo 아이템 필터링
  • 유용한 통계 표시

이 과정에서 이전에 공부한 atoms, selectors와 더불어 atom families 및 hook과 최적화를 다루게 되는데 일단 한 번 해보자.

todo 아이템 추가 및 출력

먼저 todo 아이템들의 상태를 나타낼 atoms가 필요하다. store 디렉토리 아래에 todoStore.js 라는 파일을 생성하자! 그리고 다음과 같이 todoListState 라는 atom을 작성하면 된다. default값은 아무 상태가 없는 빈 배열로 선언해줬다.
그리고 이제 App.js에서 해당 아이템들을 볼 수 있게 코드를 작성해야 한다.
그 전에 todo 아이템을 추가하는 TodoCreator 라는 컴포넌트와 TodoItem 이라는 컴포넌트를 만들어보자. 디렉토리 관리를 위해 components 라는 디렉토리를 만들고 그 안에 컴포넌트를 만드는게 좋다.

TodoCreator.js

먼저 todo 아이템을 추가할 수 있게 components라는 디렉토리 아래 TodoCreator.js 라는 컴포넌트를 만들자. 해당 컴포넌트에서는 input과 button 태그를 이용해 todo 아이템을 추가할 수 있도록 할 것이다.

// TodoCreator.js

import { useState } from "react";
import { useSetRecoilState } from "recoil";
import { todoListState } from "../store/todoStore";

function TodoCreator() {
  const [inputValue, setInputValue] = useState("");
  const setTodoList = useSetRecoilState(todoListState);

  const addItem = () => {
    setTodoList((oldTodoList) => [
      ...oldTodoList,
      {
        id: getId(),
        text: inputValue,
        inComplete: false,
      },
    ]);
    setInputValue("");
  };

  return (
    <div>
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
      />
      <button onClick={addItem}>Add</button>
    </div>
  );
}

let id = 0;
function getId() {
  return id++;
}

export default TodoCreator;

해당 컴포넌트에서는 React에서 제공하는 useState 라는 훅을 통해 input 박스의 값을 제어하고 useSetRecoilState 라는 훅을 사용해 todoListState라는 atom의 상태를 변화시켰다.
useSetRecoilState 훅은 atom의 상태를 변화시킬 수 있는 setter 함수를 반환하는데 위 코드에서는 setTodoList가 여기에 해당한다. 해당 훅은 useState 와 마찬가지로 인자로 들어오는 값이 함수가 아니라면 해당 값을 바로 상태에 할당하고, 함수라면 함수가 반환하는 값을 상태에 할당하는데 이때 인자로 들어오는 함수의 첫 번째 인자는 상태가 바뀌기 직전의 상태이다. 즉, 새로운 todo 아이템을 추가하기 전의 todo 리스트다. (oldTodoList)

TodoItem.js

todoListState 에 포함된 todo 아이템들을 하나씩 나타낼 Item 컴포넌트이다. text 값을 수정할 수 있으며, 완료한 아이템에 대해서 완료 체크 및 삭제할 수 있는 기능을 가지게 만들 것이다.

// TodoItem.js

import { useRecoilState } from "recoil";
import { todoListState } from "../store/todoStore";

const TodoItem = ({ item }) => {
  const [todoList, setTodoList] = useRecoilState(todoListState);
  const index = todoList.findIndex((listItem) => listItem === item);

  const editItemText = ({ target: { value } }) => {
    const newList = replaceItemAtIndex(todoList, index, {
      ...item,
      text: value,
    });

    setTodoList(newList);
  };

  const toggleItemCompletion = () => {
    const newList = replaceItemAtIndex(todoList, index, {
      ...item,
      isComplete: !item.isComplete,
    });

    setTodoList(newList);
  };

  const deleteItem = () => {
    const newList = removeItemAtIndex(todoList, index);

    setTodoList(newList);
  };

  return (
    <div>
      <input type="text" value={item.text} onChange={editItemText} />
      <input
        type="checkbox"
        defaultChecked={item.isComplete}
        onChange={toggleItemCompletion}
      />
      <button onClick={deleteItem}>X</button>
    </div>
  );
};

export default TodoItem;

function replaceItemAtIndex(arr, index, newValue) {
  return [...arr.slice(0, index), newValue, ...arr.slice(index + 1)];
}

function removeItemAtIndex(arr, index) {
  return [...arr.slice(0, index), ...arr.slice(index + 1)];
}

해당 컴포넌트는 전역으로 관리하고 있는 todoList를 가져와 반복문을 통해 각 todoItem에 대해 나타내는 컴포넌트이다.
해당 아이템이 전체 todoItem 중 몇 번째 아이템인지 알아야하고, 수정 및 완료 작업을 할 수 있어야 하기 때문에 useRecoilState를 통해 todoListState를 가져왔다.

  • editItemText 함수는 todo의 내용이 바뀔때 실행되는 함수로 해당 아이템의 text 값을 수정한 새로운 객체를 만들고, 하단의 replaceItemAtIndex 함수의 인자로 넘겨 기존의 배열에서 새로운 아이템으로 교체한 배열을 반환받는다. 그리고 setTodoList 함수의 인자로 넘겨 전역으로 관리하고 있는 todoListState를 갱신한다.
  • toggleItemCompletion 함수는 todo의 완료여부가 바뀔때 실행되는 함수로 해당 아이템의 isComplete 값을 수정한 새로운 객체를 만들고, 하단의 replaceItemAtIndex 함수의 인자로 넘겨 기존의 배열에서 새로운 아이템으로 교체한 배열을 반환받는다. 그리고 setTodoList 함수의 인자로 넘겨 전역으로 관리하고 있는 todoListState를 갱신한다.
  • deleteItem 함수는 해당 아이템을 삭제하는 함수로 X버튼을 클릭했을때 실행된다. 하단의 removeItemAtIndex 함수의 인자로 아이템의 index를 넘겨 기존의 배열에서 해당 아이템을 제거한 배열을 반환받는다. 그리고 setTodoList 함수의 인자로 넘겨 전역으로 관리하고 있는 todoListState를 갱신한다.

결과

profile
I Will be Relaxed Person

0개의 댓글