[TIL]2022_07_04 Recoil

hyomin·2022년 7월 3일
1

TIL

목록 보기
8/14
post-thumbnail

Recoil

Redux와 비슷하게 상태관리를 도와주는 아이이다.
세미나에 참가해서 본 웹 서비스들의 스택을 보니 redux 가 아닌 recoil이 전부였다.

https://recoiljs.org/ko/

기존에 많은 사람들이 사용중인 상태관리 라이브러리 Redux, MobX는 그저 단순 자바스크립트 상태관리 라이브러리 일뿐, 리액트를 위한 상태관리 라이브러리라는 것이다.

공식문서 탐험

Atom

Atom은 상태(state)의 일부를 나타낸다. Atoms는 어떤 컴포넌트에서나 읽고 쓸 수 있다. atom의 값을 읽는 컴포넌트들은 암묵적으로 atom을 구독한다. 그래서 atom에 어떤 변화가 있으면 그 atom을 구독하는 모든 컴포넌트들이 재 렌더링 되는 결과가 발생할 것이다.
고유한 key값을 가져야 하며 기본값 default를 설정 해줄 수 있다.

흠 약간 store 역할을 하는 것 같다

const textState = atom({
  key: 'textState', // unique ID (with respect to other atoms/selectors)
  default: '', // default value (aka initial value)
});

key 값이 unique 해야한다는 것이 포인트

function CharacterCounter() {
  return (
    <div>
      <TextInput />
      <CharacterCount />
    </div>
  );
}

function TextInput() {
  const [text, setText] = useRecoilState(textState);

  const onChange = (event) => {
    setText(event.target.value);
  };

  return (
    <div>
      <input type="text" value={text} onChange={onChange} />
      <br />
      Echo: {text}
    </div>
  );
}

호오 생각보다 간단하다

  const [text, setText] = useRecoilState(textState);

useState과 비슷하다.
미리 저장된 textState를 불러와서('key 값') text 에 value를 넣고 setText로 Handeling 하면 되다.

Selector

Selector는 파생된 상태(derived state)의 일부를 나타낸다. 파생된 상태는 상태의 변화다. 파생된 상태를 어떤 방법으로든 주어진 상태를 수정하는 순수 함수에 전달된 상태의 결과물로 생각할 수 있다.

? 뭐라는 거야

const charCountState = selector({
  key: 'charCountState', // unique ID (with respect to other atoms/selectors)
  get: ({get}) => {
    const text = get(textState);

    return text.length;
  },
});
function CharacterCount() {
  const count = useRecoilValue(charCountState);

  return <>Character Count: {count}</>;
}

봐도 모르겠다. 그래서 예시를 조금 찾아 보았다.

예를 들자면, 우리가 toDoState라는 배열의 length를 가져와 현재 할 일이 몇 개인지 확인해보고 싶다고 한다면, 우리는 해당 컴포넌트에서 그 배열을 그 안에서 가공해 사용할 수 있겠지만, 우리는 selector를 통해, 그 과정을 거치지 않는 순수한 형태의 todo.length를 얻을 수 있습니다.

출처 : https://sangjuntech.tistory.com/27
감사합니다.

이제야 보이는 함수

아까 관리하던 textState 가 있는데 이 문자의 문자길이를 계속 바라보고 있을 때 textState 에서 가져와서 text.length 로 얻을 수 있지만 따로 쪼개서 관리할 수 있다는 뜻이다.

첫번째 함수를 보면 다시 키를 만들고,

get: ({get}) => {
    const text = get(textState);
    return text.length;
  },

로 textState를 바라보면서 값을 받아오는 모습을 볼 수 있다. 약간 안드로이드의 uiState를 느낌

이거 왜 안써?, 왜 리덕스 써? 완전 좋군.

atomFamily

상태 관리를 할 때 다수의 객체를 배열의 형태로 관리해야 하는 경우가 있다.
Todo[] 형태의 Atom인 todoList를 정의하고, 해당 Todo에 여러 개의 Todo를 저장해 관리할 수 있다.

하지만 이 패턴은 Redux와 동일하게 한 개의 todo에 변경이 일어날 때마다 todoList Atom에 매번 새로운 배열이 할당 되어야한다. todoList를 이용해 여러개의 todo를 렌더링할 때 결국 별도의 memoization이 필요할 수 있다.

또한 Recoil의 사상에 따르면 Atom은 고유한 key를 갖는, 컴포넌트가 구독할 수 있는 가장 작은 단위의 상태값(원자값)이 되도록 구성하는 것이 이상적이다.

서로 다른 요소(element)를 개별 Atom으로 관리하고, 각 컴포넌트에서는 필요한 개별 Atom만을 구독함으로써 렌더링에서의 이점이 생긴다

한 배열 안에 여러 개의 todo를 관리하는 패턴에는 작동에 문제가 없지만 Recoil의 설계에는 정확히 들어맞는다고 하기 어렵다.

그렇다고 하더라도 Todo 타입을 가지는 Atom을 여러 개 정의하는 것도 애매해 보인다.

이 경우!! atomFamily API를 사용할 수 있다.

atomFamily
atomFamily는 동일한 형태의 atom을 생성해주는 팩토리 함수를 제공합니다(정확히 말하면, 팩토리 함수를 리턴하는 함수를 리턴합니다). 이름에서 혼동이 올 수 있지만, atomFamily는 그 자체로 Atom을 관리할 수 있는 배열을 제공해주는 API는 아닙니다. 즉, atomFamily를 호출할 때마다 지정한 형식의 Atom을 생성해내게 됩니다.

출처 : https://junglast.com/blog/recoil-atomfamily-atom

todo를 개개의 atom에 저장하며 이는atomFamily 를 통해 처리하는 방식이 되는 것이다.

atomFamily 는 atom과 동일하지만 인스턴스간의 구분이 가능하도록 매개변수를 받을 수 있다. 아래의 두개는 같은 코드이다.

// atom
const itemWithId = memoize(id => atom({
  key: `item-${id}`,
  default: ...
}))
// atomFamily
const itemWithId = atomFamily({
  key: 'item',
  default: ...
});

다른 점은 atomFamily 가 memoization을 처리하며 각 인스턴스마다 따로 고유의 키를 할당하지 않아도 된다. 그 역시 atomFamily 가 대신 해줄 것이다.

atom 과 atomFamily 는 기본값을 함수로 대체할 수 있다. atomFamily 는 자신이 가진 id 값을 이 함수로 넘겨준다.

profile
🌱

0개의 댓글