티스토리 뷰

const setExample1Selector = selector({
  key: "Selector/SetExample",
  get: ({ get }) => {
    const getExample1State = get(example1State);

    return getExample1State;
  },
  set: ({ get, set }, newValue) => {
  	// get을 통해 다른 atom이나 selector로 부터 값을 찾을 수 있습니다.
  	// set을 통해 값을 가져올 수 있는데,
    // 첫 번째 매개변수에는 Recoil 상태를, 두 번째 매개변수는 설정할 새로운 값입니다.
    set(example1State, newValue);
  },
});

Recoil 패키지 설치하기

// npm
$npm install recoil

// yarn
$yarn add recoil

 

 

RecoilRoot

recoil 의 상태를 전역적으로 전달해 주기 위해서는 RecoilRoot 라는 Provider 컴포넌트가 필요합니다.

redux 의 provider 과 같이 생각하면 쉽습니다.

 

RecoilRoot는 최상단의 Root 컴포넌트에 넣기에 가장 좋습니다.

App을 생성해주는 index.js 또는 App.js 와 같은 파일을 예를 들수가 있습니다.

 

import React from 'react';
import {
  RecoilRoot,
} from 'recoil';

function App() {
  return (
    <RecoilRoot>
      <Component />
    </RecoilRoot>
  );
}

 

 

앱 상태 정보 원천 Atom

Atom 은 앱 상태의 source of truth( 앱 상태 정보의 원천 )를 갖습니다.

key(atom을 구별하기 위한 유니크한 키값) 와 default(초기값)을 통해 상태를 선언합니다.

 

key, default

key : 계속해서 같은 상태를 유지할 수 있도록 도와주는 역할을 하고,

default : 기본적인 초기값을 설정합니다. 초기화시 해당 atom은 default값으로 초기화합니다.

 

구독

해당 atom값을 사용하거나 읽는 컴포넌트는 그 atom을 구독하고 있으며,

atom의 상태가 변경(업데이트)되면 구독하는 컴포넌트들은 모두 리 렌더링이 일어나게 됩니다.

import { atom } from "recoil";

const exampleState = atom({
  key: "exampleState",
  default: [1, 2, 3, 4, 5],
});

export default exampleState;

 

예시

사용할 때엔,

내보내기 한 exampleState를 recoil 의 상태를 가져오는 메서드를 사용해서 사용하면됩니다.

다음은 recoil 의 value 값을 가져오는 userRecoilValue 를 사용해서 값을 가져온 결과입니다.

import { useEffect } from "react";
import { useRecoilValue } from "recoil";
import { exampleState } from "../../../lib/recoil/atoms";

export default function Example() {
  const exampleValue = useRecoilValue(exampleState);

  useEffect(() => {
    console.log("exampleValue:", exampleValue);
    //console : exampleValue: (5) [1, 2, 3, 4, 5]
  }, []);
  return <></>;
}

 

비동기 처리와 복잡한 로직 구현 Selector

atom을 통해서 각 역할에 맞는 상태들을 key, default 를 통해서 생성해 주었습니다.

그 이후에 그 데이터를 그대로 사용할 수도 있지만,

각 데이터를 가공(필터링 등등)하거나 여러가지 동작을 수행한 후에 사용하고 싶다면

selector을 사용하면 됩니다.

비동기도 promise를 반환하는 데이터도 selector을 통해서 관리할 수 있는데,

이 부분은 다음에 알아보도록 하겠습니다.

 

Selector은 Recoil에서 함수나 파생된 상태를 나타냅니다.

key ,get, set 의 값을 지니는데 각각의 역할은 다음과 같습니다.

 

key, get, set

key : 내부적으로 atom을 식별하는데 사용되는 고유한 문자열이며,

다른 생성된 atom에서 사용한(전체적으로) key값과 상이해야하고 고유해야합니다.

get : 함수형이며, 파생된(atom으로 선언된 값을 가져옴) 상태의 값을 읽거나,

비동기적인(Promise와 같은) 값을 가져올 수 있습니다.

첫번째 매개변수로 get을 전달하며 get에는 다른 atom이나 selector 부터 값을 찾는데 사용됩니다.

set : 이 속성은 해당 selector는 쓰기 가능한 상태를 반환하게됩니다.

첫번째 매개변수에는 설정할 콜백 객체, 두번째 매개변수에 새로 입력될 값이 전달됩니다.

첫번째 매개변수 콜백 객체엔 get, set이 포함되어 있습니다.

 

예시1.

selector의 get을 이용해서

두 atoms를 병합하는 combine selector을 만들어보겠습니다.

 

1. 먼저 병합할 두 atoms를 생성해줍니다.

const example1State = atom({
  key: "Atom/Example1State",
  default: [1, 2, 3, 4, 5],
});
const example2State = atom({
  key: "Atom/Example2State",
  default: [6, 7, 8, 9, 10],
});

 

2. 그다음 combine의 기능을 수행할 selector을 생성해줍니다.

const combineExampleSelector = selector({
  key: "Selector/CompbineExample",
  get: ({ get }) => {
    const getExample1State = get(example1State);
    const getExample2State = get(example2State);
    // 두 atom 상태 배열을 concat을 통해 병합합니다
    const combinedExampleState = getExample1State.concat(getExample2State);

    return combinedExampleState;
  },
});

 

3. 그리고 사용할 컴포넌트에서 useRecoilValue를 통해서 해당 값을 읽으면

다음과 같이 합쳐진 배열이 나오게 됩니다.

export default function Example() {
  const combineExampleSelectorState = useRecoilValue(combineExampleSelector);

  useEffect(() => {
    console.log("combineExampleSelectorState: ", combineExampleSelectorState);
    // console : combineExampleSelectorState:  (10) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  }, []);
  return <></>;
}

 

예시2.

다음은 selector의 set을 사용하는 예제입니다.

 

0. atom은 미리 생성해 두었던 example1state를 사용하겠습니다.

 

1. selector을 생성해줍니다.

새로운 배열을 추가하는 로직을 작성해봅니다.

이런 간단한 로직은 atom자체를 useRecoileState 를 사용해서 바꿀 수 있지만, selector을 이용해서 구현을 해봅니다.

const setExample1Selector = selector({
  key: "Selector/SetExample",
  get: ({ get }) => get(example1State),
  set: ({ get, set }, newValue) => {
  
    // get을 통해 다른 atom이나 selector로 부터 값을 찾을 수 있습니다.
    // set을 통해 값을 가져올 수 있는데, 첫 번째 매개변수에는 Recoil 상태를,
    // 두 번째 매개변수는 설정할 새로운 값입니다.
    const prevState = [...get(example1State)];
    const calcNewValue = prevState.concat(newValue);
    set(example1State, calcNewValue);
    
  },
});

 

2. 추가할 배열을 setRecoil 해주고 해당 selector를 console 로그를 통해 확인해봅니다.

const [getExample1State, setExample1State] =
    useRecoilState(setExample1Selector);
    
useEffect(() => {
	// 해당 함수는 리엑스 strict mode로 인해 useState와 같은 상태관리를 쓰는 곳이면
    // 2번 렌더링이 일어날 것입니다. ref와 같은 hook으로 2번 렌더링 일어나는 과정을
    // 막아주거나 이를 염두하고 작업이 필요합니다.
    
    // 'add'에 번호가 붙는 배열을 추가해줍니다
    setExample1State(["add", "add2", "add3"]);
  }, []);

  useEffect(() => {
  	// 콘솔에는 다음과 같이 로그가 보이게 됩니다.
    console.log("getExample1State: ", getExample1State);
    // console : getExample1State:  (8) [1, 2, 3, 4, 5, 'add', 'add2', 'add3']
  }, [getExample1State]);

 

 

useRecoilValue , useSetRecoilState, useRecoilState, useResetRecoilState

기본적인 상태관리 메서드들입니다.

 

useRecoilValue : 읽기만 가능한 atom 및 selector 값을 불러옵니다.

useSetRecoilState : 쓰기만 가능한 atom 및 selector 값을 변경합니다.

useRecoilState : 읽기 및 쓰기가 가능한 배열 형식의 함수를 반환합니다. useState와 사용법이 거의 유사합니다.

useResetRecoilState : 해당 상태를 default로 설정한 초기값으로 초기화합니다.

 

 

... 마치며

기본적인 recoil의 사용법을 알아보았습니다. 개념만 익히고 전체적으로 한번 훑고 지나간거라,

사용법에 대한 예제를 많이 습득하지 않았지만, 초기 세팅도 간편하고 사용법도 어렵지않은 느낌이였습니다.

 

recoil의 기능은 위에서 다룬것보다 더 많고 상세한것은 더 공부할 필요가 있습니다.

페이스북에서 만들고 있는 라이브러리인 만큼 리엑트 친화적이고

정식버전으로 출시 이전임에도 프로덕트에 사용하는 곳이 많아 공부를 진행해보고 프로젝트에 적용해볼 예정입니다.

 

다음번엔 recoil을 좀 더 사용해보면서 recoil의 장점을 더 파악하고, recoil의 세부적인 내용들을 다뤄보려고 합니다.

 

댓글
최근에 올라온 글