코딩쌀롱

[React] selectorFamily, useRecoilValueLoadable 본문

개발공부

[React] selectorFamily, useRecoilValueLoadable

이브✱ 2021. 6. 25. 06:26

📌 상황1

이슈 트래커의 라벨페이지에서 라벨들을 get할 때 selector를 사용해서 response 값을 받으려고 했다. 그런데 라벨, 마일스톤을 한 selector로 받아올 수 있으면 좋을 것 같아 인자를 넘길 수 있는 selectorFamily를 사용했다. path값을 인자로 넘겨서 라벨, 마일스톤이 한 selector를 사용할 수 있게끔 했다.

 

 

selectorFamily - 공식문서

공식문서를 보면 코드가 아닌 글들은 이해하기 어렵다ㅠㅠ 좀 더 익숙해지면 이해할 수 있게 될까... selector 문서와 같이 영어로 보면서 이해하려고 노력해봤다.

 

key: 내부적으로 atom을 식별하는데 사용되는 고유한 문자열, 앱 전체의 atom, selector에 대해 고유해야 함! key값이 똑같은 게 있다면 오류가 발생한다. 그리고, 경험으로 알게 됐다..키가 같으면 상태가 변할 때 같이 변한다는 것을..으휴

 

 get:

  → A function that is passed an object of named callbacks that returns the value of the selector.

  → This is wrapped by a function which is passed the parameter from calling the selector family function.

 셀렉터의 값을 반환하는 콜백함수들의 객체를 전달받는 함수.. selector의 get을 사용할 때 매개변수로 객체가 전달되는데 그 객체 안에는 get, getCallback과 같은 이름이 있는 함수들이 들어있다. destructuring 사용해서 ({get})이렇게 사용했던 것처럼 get함수가 들어있는 객체를 전달받는다는 내용인 것 같다.

 콜백이 담긴 객체를 전달받기도 하지만 매개변수도 받는다. 그래서 커링함수의 형태로 되어있다. (param) => ({get}) => {} 이런 식으로. 그래서 selectorFamily 함수가 호출될 때 전달받은 파라미터로 래핑된다고 한 것 같다.

 

set:

  → An optional function that will produce writeable selectors when provided. It should be a function that takes an object of named callbacks, same as the selector() interface.

  → This is again wrapped by another function with gets the parameters from calling the selector family function.

 쓰기가능한(값을 변경할 수 있는) selector를 생성하는 함수이고, optional이다. selector처럼 콜백 객체를 가지고 있다. set도 get과 마찬가지로 파라미터를 가진 함수로 매핑된다. (param) => ({set}) => {} 이렇게.

 

공식문서 예시 코드

// atom 값
const myNumberState = atom({
  key: 'MyNumber',
  default: 2,
});

// selectorFamily (set은 optional)
const myMultipliedState = selectorFamily({
  key: 'MyMultipliedNumber',
  get: (multiplier) => ({get}) => {
    return get(myNumberState) * multiplier;
  },
  set: (multiplier) => ({set}, newValue) => {
    set(myNumberState, newValue / multiplier);
  },
});

function MyComponent() {
  // defaults to 2
  const number = useRecoilValue(myNumberState);

  // defaults to 200
  const multipliedNumber = useRecoilValue(myMultipliedState(100));

  return <div>...</div>;
}

반환값을 사용할 때는 useRecoilValue(selectorFamily(arg)) 이렇게.

selector에 매개변수가 추가된 것!

 

path를 매개변수로 받아 요청주소에 따라 결과값을 받을 수 있도록 했다.

export const LabelOrMilestone = selectorFamily({
  key: 'LabelOrMilestone',
  get: (path: string) => async () => {
    try {
      const url = `${baseURL}/${path}`;
      const res = await fetchWithAuth(url, labelErrorMsg);
      const jsonData = res.json();
      return jsonData;
    } catch (error) {
      if (typeof error === 'object') throw urlErrorMsg;
      throw error;
    }
  },
});

 

📌 상황2

useRecoilValueLoadable을 사용해서 selectorFamily에 있는 fetch의 결과에 따라 loading, error, rendering 처리를 해주면 좋을 것 같아 사용했다.

 

useRecoilValueLoadable - 공식문서

 비동기 selector의 값을 읽기 위해 사용. 주어진 상태에 컴포넌트를 암묵적으로 구독한다.

 

‣ 매개변수: atom 혹은 selector

반환값: Loadable 객체

 

state 'hasValue' 'hasError' 'loading'
contents 실제 값 Error 객체 값의 Promise

 

 

function LabelTable() {
  const { state, contents } = useRecoilValueLoadable(
    LabelOrMilestone('labels')
  );

  return (
    <LabelTableWrap>
      <TableHeader />
      {state === 'loading' && <LabelsSkeleton />}
      {state === 'hasError' && <ErrorLabel>{contents}</ErrorLabel>}
      {state === 'hasValue' &&
        contents.map((labelInfo: labelInfoType) => {
          return (
            <LabelCell
              key={labelInfo.id}
              labelInfo={labelInfo}
            />
          );
        })}
    </LabelTableWrap>
  );
}

state 값에 따라 렌더링되는 컴포넌트가 다르게 해주었다.

 

 

'개발공부' 카테고리의 다른 글

[LeetCode_JS] 283. Move Zeroes _array  (0) 2021.07.17
기술 아티클 읽고 메모📚_7월  (0) 2021.07.07
[Algorithm] Quick Sort  (0) 2021.06.15
[Web¦Browser] local, session, cache, cookie  (0) 2021.06.07
Comments