JS' 공부흔적

[Recoil] 리코일의 기본 개념 (3) - selector 본문

Recoil

[Recoil] 리코일의 기본 개념 (3) - selector

이준수 2022. 11. 26. 20:55

이번 글에서는 리코일의 selector에 대해 알아보도록 하겠다.

selector

selector는 리코일에서 관리하는 상태의 특정 부분만 선택할 때 사용한다. selector를 사용하는 이유는 최소한의 상태 집합만 atoms에 저장하고, 다른 모든 파생되는 데이터는 selectors에 명시한 함수를 통해 효율적으로 계산함으로써 쓸모없는 상태의 보존을 방지하기 위함이다. 아래에 나올 코드에 대해 미리 말하자면, TempFahrenheit만을 atom에 저장하고, 이로부터 파생되는 tempCelcius는 굳이 보존하지 않기 위해 selector를 사용했다. selector는 key와 get 함수를 필수로 받아야한다. 또한 set 함수도 선택적으로 받을 수 있는데, get 함수만 사용하게 되면 selector는 읽기만 가능한 ReadOnly 상태이고, set 함수도 사용하게 되면 쓰기도 가능한 상태가 된다. 또한, get 함수에서 의존하고 있는 상태의 값이 변경되면 selector도 다시 평가된다. selector를 이해하기 위한 예시로 섭씨 및 화씨 온도를 계산하는 코드를 사용하겠다. 참고로 이는 리코일 공식 문서에서 예시로 제공하는 코드이다.

import {
  atom,
  selector,
  useRecoilState,
  DefaultValue,
  useResetRecoilState,
} from "recoil";

const tempFahrenheit = atom({
  key: "tempFahrenheit",
  default: 32,
});

const tempCelcius = selector({
  key: "tempCelcius",
  get: ({ get }) => ((get(tempFahrenheit) - 32) * 5) / 9,
  set: ({ set }, newValue) =>
    set(
      tempFahrenheit,
      newValue instanceof DefaultValue ? newValue : (newValue * 9) / 5 + 32 // DefaultValue일 땐 값 재설정인 경우임
    ),
});

function TempCelcius() {
  const [tempF, setTempF] = useRecoilState(tempFahrenheit);
  const [tempC, setTempC] = useRecoilState(tempCelcius);
  const resetTemp = useResetRecoilState(tempCelcius);

  const addTenCelcius = () => setTempC(tempC + 10);
  const addTenFahrenheit = () => setTempF(tempF + 10);
  const reset = () => resetTemp();

  return (
    <div>
      Temp (Celcius): {tempC}
      <br />
      Temp (Fahrenheit): {tempF}
      <br />
      <button onClick={addTenCelcius}>Add 10 Celcius</button>
      <br />
      <button onClick={addTenFahrenheit}>Add 10 Fahrenheit</button>
      <br />
      <button onClick={reset}>Reset</button>
    </div>
  );
}

export default TempCelcius;

화씨 온도를 나타내는 Fahrenheit는 atom을 선언했고, 섭씨 온도를 나타내는 Celcius는 selector를 사용하여 tempFahrenheit에 의존한다. selector를 살펴보면 우선 get 함수에선 화씨 온도를 불러와서 섭씨 온도로 변환해준다. set 함수에선 newValue값을 받는다. 이렇게 get, set 함수를 모두 사용하여 selector를 선언하게 되면 위의 코드처럼 useRecoilState로 상태를 관리할 수 있다. 참고로 get 함수만 사용하게 되면 useRecoilState를 사용할 수 없다.

set: ({ set }, newValue) =>
    set(
      tempFahrenheit,
      newValue instanceof DefaultValue ? newValue : (newValue * 9) / 5 + 32 // DefaultValue일 땐 값 재설정인 경우임
    ),

위 코드를 보면 set함수는 2개의 인자를 받는데, 첫 번째 인자의 값을 두 번째 인자의 값으로 설정한다는 의미이다. 즉, 화씨 온도를 newValue를 사용하여 가공된 값으로 설정한다는 의미이다. 이때 newValue instanceof DefaultValue가 나오는데, 이는 말 그대로 newValue가 DefaultValue의 인스턴스인지 확인하는 과정이다. 이것을 쓴 이유는 이전 글에서 다뤘던 useResetRecoilState 훅에 대비하기 위함이다. newValue가 DefaultValue의 인스턴스라는 것은 useResetRecoilState가 쓰였다는 뜻이다. 즉, 값을 초기화한다는 뜻이므로 newValue 값을 가공하면 안 된다.

그렇지 않을 경우에는 섭씨 온도로 들어온 newValue값을 가공하여 화씨 온도로 변경해준다.

 

결국 setTempF와 setTempC 모두 tempFahrenheit값을 변경하게 되는데, setTempC의 경우 get 함수에서 tempFahrenheit를 의존하고 있으므로 이 값이 변경되면 selector도 다시 평가가 되는 것이다. 따라서 tempFahrenheit를 변경하게 되더라도 tempCelcius도 변경이 된다.

이렇게 되면 섭씨 온도를 10 더하든, 화씨 온도를 10 더하든 두 값이 모두 업데이트가 된다.

실행 결과는 아래와 같다.

728x90
반응형