상태 관리 라이브러리 - Recoil (2. Atom)

eeensu·2023년 8월 5일
0
post-thumbnail

recoil에서 사용하는 주요 개념들을 간략하게 설명하자면,

  • RecoilRoot
    recoil을 사용하기 위해서는 애플리케이션의 최상위 컴포넌트에서 RecoilRoot 컴포넌트를 사용해야 한다. 이 컴포넌트는 recoil 상태와 상태 업데이트를 관리하는데 필요한 컨텍스트를 제공한다.

  • Atoms
    atoms는 컴포넌트가 구독할 수 있는 상태의 기본 단위다. 상태를 정의하고 사용할 때 사용되며, 컴포넌트에서 이 atom에 접근하여 읽거나 업데이트할 수 있다.

  • Selectors
    atom들의 파생된 상태를 계산하는 함수이다. selector를 사용하여 복잡한 상태를 효과적으로 계산하고 공유할 수 있다.

  • Suspense
    recoil은 react의 Suspense 기능과 함께 사용할 수 있다. Suspense를 통해 비동기적으로 데이터를 불러오거나 상태를 업데이트할 때 자연스럽게 대응할 수 있다.



recoil을 사용하면 atoms (공유 상태)에서 selectors (순수 함수)를 거쳐 컴포넌트로 내려가는 data-flow graph를 만들 수 있다. 오늘 할일의 목록을 생성하고, 추가하고, 삭제하는 예제를 통해 recoil을 사용하는 법을 알아보자.

Atom

컴포넌트가 구독할 수 있는 상태의 단위이다. recoil을 사용하면 atoms (공유 상태)에서 selectors (순수 함수)를 거쳐 컴포넌트로 내려가는 data-flow graph를 만들 수 있다.
또한 상태의 업데이트와 구독이 가능하다. atom이 업데이트되면 각각 구독된 컴포넌트는 새로운 값을 반영하여 다시 렌더링 된다. 동일한 atom이 여러 컴포넌트에서 사용되는 경우 모든 컴포넌트는 상태를 공유한다.

  1. Todo의 타입 지정
// 할일의 목록을 담은 객체
export interface Todo {
    id: ID;						// 고유 ID
    task: string;				// 할일
    isDone: boolean;			// 수행 여부
}

  1. store 폴더 생성
    recoil의 경우 state를 전역적으로 관리하는 store 폴더에 todoStore 처럼 state의 이름을 담은 파일을 생성하는 것이 관례이자 유지보수에 효과적이다. 해당 파일에 다음과 같이 입력한다.
export const todoListState: RecoilState<Todo[]> = atom({
    key: 'todoListState',
    default: [] as Todo[],
});

Atoms는 디버깅, 지속성 및 모든 atoms의 map을 볼 수 있는 특정 고급 API에 사용되는 고유한 키가 필요하다. 두 개의 atom이 같은 키를 갖는 것은 오류이기 때문에 키값은 전역적으로 고유하도록 해야한다.


  1. 컴포넌트에서 해당 state를 구독
    recoil에서 제공하는 atom state를 구독하는 hook은 useRecoilValue() 이다. 인자에 store에서 구현한 state를 넣어주고atom을 통해 구독한 todoList state를 받아와 배열의 .map 함수를 활용하여 아이템들을 목록에 그려준다. 초기값은 빈 배열이기에 아직 아무것도 없다.
const TodoList: FC = () => {

  const todoList = useRecoilValue<Todo[]>(todoListState); 

  return (
    <div>        
      {todoList.map((todo) => (
        <TodoItem 
          key={todo.id} 
          id={todo.id} 
          task={todo.task} 
          isComplete={todo.isComplete}
         />
      ))}
    </div>
  );
};

export default TodoList;

  1. state의 변경 (Todo 목록 추가)
    Todo에 목록을 추가하는 것은 기존 Todo 상태를 업데이트하는 것이고, 이를 업데이트 하게 해주는 hook은 useRecoilState()이며, 리턴값은 useState()와 동일하다. 이때, settter 함수만 쓰고 싶으면 useSetRecoilState() hook을 사용한다.
// 새로 생성되는 todo의 ID를 지정해주는 함수
let id = 0;
function getId(): string {
    return String(id++);
}

const InputTodo: FC = () => {

    const [text, setText] = useState<string>('');				
    const setTodoList = useSetRecoilState<Todo[]>(todoListState);
  
    const handleAdd = () => {
      	// 스프레드(...) 연산자로 기존의 배열을 가져온 뒤, 새 Todo를 같이 넣어준다.
        setTodoList(p => [...p, {
            id: getId(),
            isComplete: false,
            task: text
        }]);
    };

    return (
        <div>
           <input value={text} onChange={(e) => setText(e.target.value)}/> 
           <button onClick={handleAdd}>Add!</button>
        </div>
    );
};

export default InputTodo;

이제 위의 컴포넌들과 기타 등을 조합하면 다음과 같이 완성된다.

profile
안녕하세요! 26살 프론트엔드 개발자입니다! (2024/03 ~)

0개의 댓글