[React] Recoil_hooks

안승찬·2024년 4월 3일

React

목록 보기
9/9

본 게시물은 Recoil Hooks에 대한 내용을 담고 있습니다.

useRecoilState

  • atom이나 selector의 값을 사용할 때 사용
  • recoil 상태를 인자로 받는다.
  • selector의 경우 set을 설정해주지 않으면 사용하지 못한다.
const [count, setCount] = useRecoilState(countState);

const increaseCount = () => {
	setCount(count + 1);
}

EX)


// 1. state에 정의된 QuizDifficulty.ts를 불러오는 방법
import { QuizDifficultyState } from 'src/state';

...
const QuizDifficulty = () => {
  // 2. recoilState의 사용방법 : Hook처럼 사용방법
  const [quizDifficulty, setQuizDifficulty] = useRecoilState(
    QuizDifficultyState,
  )

  const handleChange = (e: ChangeEvent<HTMLSelectElement>) => {
    setQuizDifficulty(e.target.value);
  };

  return (
    <select
      data-testid={DIFFICULTY_SELECT_TEST_ID}
      margin="16px 0px"
      value={quizDifficulty}
      onChange={handleChange}
    >
    </select>
  );
};```


### useRecoilValue

-	useRecoilState의 기능 중 get 만을 위한 hook
-	recoil state의 값을 반환


```javascript
const count = useRecoilValue(countState);

useRecoilState

  • atom이나 selector의 값을 초기화할 때 사용
  • atom과 selector의 경우 다르게 사용
const count = useRecoilValue(countState);

EX)

const resetCount = useResetRecoilState(countState);
...
<button onClick={resetCount}>reset count</button>

* atom 등록 시의 default값으로 atom을 되돌린다.

selector

import { DefaultValue, selector } from "recoil";
import countState from "../atom/countState";

export default selector({
    key: "countSelector",
    get: ({get}): number => {
        const count = get(countState);
        return count + 1;
    },
    set: ({set, get}, newCount:any)=>{
        return set(
            countState,
            newCount instanceof DefaultValue ? newCount : newCount+10,
        )
    }
})
  • set은 DefaultValue 객체를 매개변수로 전달
  • 떄문에 selector에서 set을 사용할 때 조건 처리를 해주어야 한다.
  • 일반적으로 set을 할 경우 받아온 카운트에 10을 더해서 반환하지만, DefaultValue가 오게 되면 초깃값을 반환

스냅샷

변하지 않는 정적인 데이터를 보관하려고 상태 관리 라이브러리를 사용하지는 않을 것이다. 상태는 끊임없이 변한다. 스냅샷은 계속 변하는 상태의 "한 순간"이다. 상태가 동영상이라면 스냅샷은 동영상의 한 프레임인 것이다.

스냅샷 얻기

스냅샷은 세 가지 방식을 통해 가져올 수 있다. 모두 역할이 조금씩 다르기는 하지만useRecoilSnapshot(), useRecoilTransactionObserver(), useRecoilCallback()이라는 훅을 사용해 스냅샷을 구할 수 있다.

useRecoilSnapshot()

	import {useRecoilSnapshot} from "recoil ";
	function SnapshotCount() {
      const snapshotList = useRef([]);
      const snapshot = useRecoilSnapshot();
      
      useEffect(()=>{
        snapshotList.current = [...snapshotList.current, snapshot];
      },[])
      
      return (
        <p>Snapshot count: {snapshotList.current.lenth}</p>
        )

카운터의 값이 증가하면 상태가 변하고, 따라서 보관된 스냅샷의 갯수도 증가할 것이다. 카운터의 값이 증가하면 상태가 변하고, 따라서 보관된 스냅샷의 갯수도 증가할 것이다. 스냅샷은 상태가 변할 때마다 생성된다. 따라서 SnapshotCount 컴포넌트는 상태가 변할 때마다 렌더링 된다.

useRecoilTransactionObserver()

이 훅에 전달된 콜백 함수는 아톰 상태가 변경될 때마다 호출되지만 여러 업데이트가 동시에 일어나는 경우에는 묶어서 한 번만 호출될 수도 있다.

첫 번째 인수로 호출할 콜백 함수를 전달한다. 콜백 함수에 전달되는 첫 번째 인수는 snapshot과 previousSnapshot이라는 프로퍼티를 가진 객체인데 각각 현재 스냅샷과 이전 스냅샷을 의미한다. 공식 문서에 나타난 정의를 살펴보면 다음과 같다.

function useRecoilTransactionObserver_UNSTABLE(({
  snapshot: Snapshot,
  previousSnapshot: Snapshot,
}) => void)

보관 예제

import {useRecoilTransactionObserver_UNSTABLE} from 'recoil';

function SnapshotCount() {
  const snapshotList = useRef([]);

  useRecoilTransactionObserver_UNSTABLE(({snapshot}) => {
    snapshotList.current = [...snapshotList.current, snapshot];
    console.log("Snapshot updated", snapshotList);
  });

  return (
    <p>Snapshot count: {snapshotList.current.length}</p>
  );
}

useRecoilSnapshot()과 아주 큰 차이가 있다. useRecoilTransactionObserver는 컴포넌트를 다시 렌더링하지 않는다. 따라서 출력 결과물인 "Snapshot count" 부분의 숫자가 변경되지 않는다. 콘솔을 살펴보면 분명 콜백 함수는 상태가 변경될 때마다 실행되고 있지만 컴포넌트 렌더링에는 영향을 주지 않는 것이다. 스냅샷은 구할 수 있으면서도 컴포넌트를 다시 렌더링하지 않으므로 성능 면에서 분명한 이득이 있다.

useRecoilCallback()

useCallback과 같이 의존성에 따라 갱신되는 메모이즈된 함수를 생성한다. 다만, 생성된 함수에 스냅샷과 상태를 다루는 객체 및 함수가 함께 전달된다는 점이 다르다.

useCallback처럼 첫 번째 인수에는 메모이즈할 함수가 전달되고 두 번째 인수에는 의존성이 전달된다. 주의할 점은 useRecoilCallback에서 첫 번째 인수는 스냅샷 관련 기능을 전달하기 위해 한 번 더 감싸진 "실행할 함수를 만드는 함수"라는 것이다.

const log1 = useCallback(() => {
  console.log('called with ', 'nothing');
});
const log2 = useRecoilCallback(({snapshot}) => () => {
  console.log('called with ', snapshot);
});

useRecoilCallback에서 생성된 함수의 첫 번째 인수로 전달되는 객체에는 snapshot 객체 외에도 gotoSnapshot 함수, set 함수, reset 함수가 포함되어 있다.

import {useRecoilCallback} from 'recoil';

function SnapshotCount() {
  const [snapshotList, setSnapshotList] = useState([]);
  const updateSnapshot = useRecoilCallback(({ snapshot }) => () => {
    setSnapshotList(prevList => [...prevList, snapshot]);
  });

  return (
    <div>
      <p>Snapshot count: {snapshotList.length}</p>
      <button onClick={updateSnapshot}>현재 스냅샷 보관</button>
    </div>
  );
}

스냅샷에서 상태값 가져오기

스냅샷 객체에는 getPromise와 getLoadable이라는 메소드가 있는데 이를 통해 상태값을 가져올 수 있다.

function SnapshotCount() {
  const [snapshotList, setSnapshotList] = useState([]);
  const updateSnapshot = useRecoilCallback(({ snapshot }) => async () => {
    const count = await snapshot.getPromise(counter);
    console.log("Count: ", count);

    setSnapshotList(prevList => [...prevList, snapshot]);
  });

  return (
    <div>
      <p>Snapshot count: {snapshotList.length}</p>
      <button onClick={updateSnapshot}>현재 스냅샷 보관</button>
    </div>
  );
}

0개의 댓글