코딩쌀롱
[React] selectorFamily, useRecoilValueLoadable 본문
📌 상황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 |