본문 바로가기

웹 프레임워크/Javascript - React.js

[Javascript] React - Recoil 상태관리 라이브러리

728x90

Atom

  • 상태의 단위를 나타냄
  • Atom이 업데이트 되면 해당 Atom을 구독하고 있던 모든 컴포넌트들이 새로운 값으로 Re-render됨
  • 또한 여러 컴포넌트에서 같은 Atom을 구독하고 있으면 그 컴포넌트들이 상태를 동일하게 공유
  • 고유한 key와 기본값(default)을 정의해야 함
const productState = atom({
  key: 'productState', // 이 값은 어떤 Atom이든지 Unique해야함
  default: '',
});
  • 동적 key를 가진 다른 상태를 생성하는 것도 가능
  • 여러개의 비슷한 데이터를 다룰 때 리스트에 보관하는 대신 각자의 상태가 독립되어 변경한 아이템 하나만이 업데이트 하게 됨
    (0.0.8버전 이후로 atomFamily라는 이름으로 이 기능을 대체하게 됨)
    (이동)
const productDetailState = (id) => atom({
  key: `product-state-${id}`
  default: '',
});

UseRecoilState

  • Hook의 useState와 유사
// recoil.js

import { atom } from 'recoil';

export const countState = atom({
  key: 'counter',
  default: 0,
});

// index.js
import React from 'react';
import { useRecoilState } from 'recoil';
import { countState } from './recoil';

const Index = () => {
  const [count, setCount] = useRecoilState(countState);

  const handleAddCounter = () => {
    let tempCount = count;
    setCount(tempCount + 1);
  };

  return (
    <div>{count}</div>
    <button type="button" onClick={handleAddCounter}>+</button>
  );
};

UseRecoilValue

  • 상태를 설정할 수 있는 useRecoilState를 쓰지 않고 값만을 가져올 때 사용
// recoil.js

import { atom } from 'recoil';

export const countState = atom({
  key: 'counter',
  default: 0,
});

// index.js
import React from 'react';
import { useRecoilValue } from 'recoil';
import { countState } from './recoil';

const Index = () => {
  const count = useRecoilValue(countState);

  return <div>{count}</div>;
};

UseSetRecoilValue

  • 값을 불러오지 않고 상태만을 설정할때 사용
// recoil.js

import { atom } from 'recoil';

export const countState = atom({
  key: 'counter',
  default: 0,
});

// index.js
import React from 'react';
import { useSetRecoilValue } from 'recoil';
import { countState } from './recoil';

const Index = () => {
  const setCount = useSetRecoilValue(countState);

  const handleAddCounter = () => setCount(count + 1);

  return (
    <button type="button" onClick={handleAddCounter}>+</button>
  );
};

useResetRecoilValue

  • Atom으로 정의한 상태를 초기값으로 재설정
// recoil.js

import { atom } from 'recoil';

export const countState = atom({
  key: 'counter',
  default: 0,
});

// index.js
import React from 'react';
import { useRecoilState } from 'recoil';
import { countState } from './recoil';

const Index = () => {
  const [count, setCount] = useRecoilState(countState);

  const resetCount = useResetRecoilValue(countState);

  const handleResetCounter = () => resetCount();

  const handleAddCounter = () => {
    let tempCount = count;
    setCount(tempCount + 1);
  };

  return (
    <div>{count}</div>
    <button type="button" onClick={handleAddCounter}>+</button>
    <button type="button" onClick={handleResetCounter}>reset</button>
  );
};

Selector

  • 다른 Atom 혹은 Selector들을 받아 사용하는 순수 함수
  • 특정 Atom 또는 Selector가 업데이트 시, Selector함수는 Re-evaluate됨
  • Atom처럼 컴포넌트에서 구독할 수 있으며, Selector함수가 Re-evaluate 될때, 컴포넌트는 Re-render됨
  • Selector에는 Atom처럼 고유한 Key값이 있으며, getter와 setter가 존재함
  • 이것으로 비동기적 함수를 구성하는 것도 가능함
    • 컴포넌트 화하여 비동기적 함수를 구현시엔 반드시 React.Suspense로 감싸줘야 함
// recoil.js
import { atom, selector } from 'recoil';

export const fontSizeState = atom({
  key: 'fontSizeState',
  default: 14,
});

export const fontSizeLabelState = selector({
  key: 'fontSizeLabelState',
  get: ({ get }) => {
    const fontSize = get(fontSizeState);
    const unit = 'px';

    return `${fontSize}${unit}`;
  },
});

// index.js
import React, { useCallback } from 'react';
import { useRecoilValue, useRecoilState } from 'recoil';
import { fontSizeState, fontSizeLabelState } from './recoil';

const Index = () => {
  const [fontSize, setFontSize] = useRecoilState(fontSizeState);
  const fontSizeLabel = useRecoilValue(fontSizeLabelState);

  const handleClick = useCallback(() => {
    setFontSize(size => size + 1);
  }, [setFontSize]);

  return (
    <div>
      <p>현재 폰트 크기: {fontSizeLabel}</p>
      <button type="button" onClick={handleClick}>폰트 +</button>
      <div style={{ fontSize }}>리코일 연습중</div>
    </div>
  );
};
728x90