관리 메뉴

Dev Blog

상태관리, 이제 Recoil 하세요_리뷰&정리 본문

Development Notes/State Management

상태관리, 이제 Recoil 하세요_리뷰&정리

Nomad Kim 2021. 11. 21. 12:12

리코일의 핵심 컨셉

- React 내부상태만 이용

- 작은 Atom 단위로 상태관리

- 순수함수 Selector

- 상태끼리의 상호의존성

- 읽기전용과 쓰기전용

 

 

Basic Concept

1. Atom 이 하나의 상태의 단위이며, 상태를 전역에서 관리할 수 있다.

const fontSizeState = atom({
  key: 'fontSizeState',
  default: 14,
});
function FontButton() {
  const [fontSize, setFontSize] = useRecoilState(fontSizeState);
  return (
    <button onClick={() => setFontSize((size) => size + 1)} style={{fontSize}}>
      Click to Enlarge
    </button>
  );
}

2.Selector

Selector 라는 순수함수를 이용하여 해당 Atom 을 참조하여 상태 변화가 있을 때 해당 컴포넌트만 리렌더링 된다.

Selector 내부에서 데이터를 가공하거나 유효서 검사 등 추가적인 로직을 적용할 수 있다.

If only a get function is provided, the selector is read-only and returns a RecoilValueReadOnly object. If a set is also provided, it returns a writeable RecoilState object.

function selector<T>({
  key: string,

  get: ({
    get: GetRecoilValue,
    getCallback: GetCallback,
  }) => T | Promise<T> | RecoilValue<T>,

  set?: (
    {
      get: GetRecoilValue,
      set: SetRecoilState,
      reset: ResetRecoilState,
    },
    newValue: T | DefaultValue,
  ) => void,

  dangerouslyAllowMutability?: boolean,

  cachePolicy_UNSTABLE?: CachePolicy,
})

3. 상태들의 상호 의존성

각 상태들은 상호 의존성을 가질 수 있기 때문에 유기적인 관리가 가능하다. 즉, selector 내부에서 다른 atom 이나 selector 참조할 수 있는데(구독), 구독하고 있는 상태가 변경되면 해당 selector 가 이를 감지하고 재평가되어 다시 렌더링 된다. 필터의 상태 변화에 따라 리스트의 상태가 변경된다. 

 

4. 읽기 전용과 쓰기 전용, 리셋 전용 등의 함수가 있다. 

1) 읽기 전용

Using this hook in a React component will subscribe the component to re-render when the state is updated. 

function useRecoilValue<T>(state: RecoilValue<T>): T;
import {atom, selector, useRecoilValue} from 'recoil';

const namesState = atom({
  key: 'namesState',
  default: ['', 'Ella', 'Chris', '', 'Paul'],
});

const filteredNamesState = selector({
  key: 'filteredNamesState',
  get: ({get}) => get(namesState).filter((str) => str !== ''),
});

function NameDisplay() {
  const names = useRecoilValue(namesState);
  const filteredNames = useRecoilValue(filteredNamesState);

  return (
    <>
      Original names: {names.join(',')}
      <br />
      Filtered names: {filteredNames.join(',')}
    </>
  );
}

2) 쓰기 전용 

Using useSetRecoilState() allows a component to set the value without subscribing the component to re-render when the value changes.

function useSetRecoilState<T>(state: RecoilState<T>): SetterOrUpdater<T>;

type SetterOrUpdater<T> = (T | (T => T)) => void;
import {atom, useSetRecoilState} from 'recoil';

const namesState = atom({
  key: 'namesState',
  default: ['Ella', 'Chris', 'Paul'],
});

function FormContent({setNamesState}) {
  const [name, setName] = useState('');
  
  return (
    <>
      <input type="text" value={name} onChange={(e) => setName(e.target.value)} />
      <button onClick={() => setNamesState(names => [...names, name])}>Add Name</button>
    </>
)}

// This component will be rendered once when mounting
function Form() {
  const setNamesState = useSetRecoilState(namesState);
  
  return <FormContent setNamesState={setNamesState} />;
}

 

3) 리셋 전용

전역에서 상태를 관리하기 때문에 특정 값으로 변경하지 않으면 이전 값을 유지하게 되어 다른 컴포넌트에 영향을 줄 수 있다. 따라서 컴포넌트가 언마운트 되는 시점에 상태 초기화를 시켜주는 함수를 이용한다. 

import {todoListState} from "../atoms/todoListState";

const TodoResetButton = () => {
  const resetList = useResetRecoilState(todoListState);
  return <button onClick={resetList}>Reset</button>;
};

How to get Asynchronous Data

const currentUserNameQuery = selector({
  key: 'CurrentUserName',
  get: async ({get}) => {
    const response = await myDBQuery({
      userID: get(currentUserIDState),
    });
    return response.name;
  },
});

function CurrentUserInfo() {
  const userName = useRecoilValue(currentUserNameQuery);
  return <div>{userName}</div>;
}

1. Suspense & Loadable

내부 상태만 이용하던 것과는 달리 서버에서 데이터를 불러오므로 idx 라는 상태를 만들어, 이 idx 값이 변경됨에 따라 새로운 데이터를 fetch 해 올 수 있도록 한다. 다만 비동기 recoil 상태를 사용할 때는 Suspense 또는 Loadable 을 함께 사용해야 에러가 발생하지 않는다. 

1) Suspense 

2) Loadable  

2. 비동기 데이터 갱신하는 방법

동일한 데이터를 여러 API 에서 사용하는 경우, 데이터를 가져오는 시점(캐싱)과 실제 데이터를 사용하는 시점의 차이로 인해 업데이트된 데이터를 반영하지 못하는 경우가 생긴다. 

 

비동기 데이터 갱신에 영향을 주는 요소

1. 내부에서 구독중인 다른 Recoil state 의 변경을 감지한 경우

2. 요청 파라메터가 완전 새로운 값으로 변경된 경우 

 

API 로 통신을 하는 횟수를 저장하는 Atom 인 Req ID Atom 을 이용!!!

두가지 방법

1) RequestID 이용한 명시적 갱신

2) Setter 활용

명시적 / 주기적 업데이트 의 활용법

 

 

 

What to consider at Initial Desining Recoil Structure

 

출처

문서: 리코일 공식웹

영상: 상태관리, 이제 Recoil 하세요_FEconf2021

'Development Notes > State Management' 카테고리의 다른 글

LocalStorage & SessionStorage & Cookie  (0) 2021.04.06
Comments