-
recoil, recoil-persistFW, Lib 공부/React 2022. 7. 20. 16:12
useState의 사용이 익숙해질 무렵, 한 가지 불편함을 느꼈다.
부모 컴포넌트에서 자식 컴포넌트로 useState안의 값을 넘겨줘야 하는 경우, 부모-자식이 한 두 단계정도 떨어져 있을 때는 상관이 없는데, 3회 이상 상속을 시켜줘야 하는 경우에는 불편함이 많았다.
이 때, recoil을 알게 되었고, 불편함이 바로 해소되었다..!
recoil - 공식 문서 페이지
recoil은 리액트를 위한 상태관리 라이브러리로, 기존에 쓰던 useState가 지역변수 같은 느낌이었다면, recoil은 전역변수 같은 느낌이었다.
그럴만 한게, recoil은 상태를 별도의 코드 파일로 작성하고, 어떠한 컴포넌트 파일에서 상태값을 불러오고, 수정할 수 있게 해준다.
뿐 만 아니라, 필터링의 기능도 구현할 수 있어, 리스트나 객체를 하나만 만들어서 여러 상황에 적용할 수 있기에 데이터 관리도 용이하다.
오늘 작성하는 내용은 내가 recoil을 쓰면서 가장 많이 사용했던 기능과 hook를 정리하고자 한다.
1. atom
atom은.. 생성자의 역할을 하는 함수이다.
인자로는 객체 하나를 받는데, 사용하야 하는 키 값이 정해져 있다.
key, default, effect_UNSTABLE 이렇게만 사용해봤다.
effect 대신에 effect_UNSTABLE을 사용했던 이유는 recoil-persist 때문인데, 자세한 내용은 뒤에서...
key는 atom의 고유 식별자로, 문자열을 값으로 받는다.
default는 초기화될 때, 기본으로 저장되는 값으로, 값, 배열, 객체 등을 값으로 받을 수 있다.
effect는 초기화될 때, 우선 순위에 따라 호출되는 atom effect 함수들의 배열을 참조할 수 있다.
export const categoriesState = atom<ICategories[]>({ key: "categories", default: [ { title: "To Do", id: 0 }, { title: "Doing", id: 1 }, { title: "Done", id: 2 }, ], effects_UNSTABLE: [persistCategory], });
이런식으로 사용한다.
이렇게 생성된 atom은 recoil에서 제공하는 여러 hook을 통해 접근, 수정이 가능하다.
1-1. useRecoilValue()
const category = useRecoilValue(categoryState);
useRecoilValue는 atom을 인자로 받고, 그 안에 저장되어 있는 데이터를 리턴해준다.
1-2. useSetRecoilState()
const setCategory = useSetRecoilState(categoryState); setCategory({key: value});
useSetRecoilState는 atom을 인자로 받고, 그 데이터를 수정할 수 있는 함수를 리턴해준다.
1-3. useRecoilState()
const [category, setCategory] = useRecoilState(categoryState);
useRecoilState는 atom을 인자로 받고, 그 안에 저장되어 있는 데이터와 수정할 수 있는 함수를 리턴해준다.
1-1, 1-2 내용을 모두 커버하고, useState와 사용방법도 동일하다.
2. selector
selector는 recoil에서 함수나, 파생된 상태를 나타낸다.
인자로는 역시 객체 하나를 받는데, 사용하야 하는 키 값이 정해져 있다.
key, get, set만 사용해봤다.
key는 atom의 고유 식별자로, 문자열을 값으로 받는다. 이 때, atom과 selector 사이의 키 값도 중복되선 안 된다.
get은 파생된 상태를 평가하는 함수를 값으로 받아야 한다. 이 때 첫 번째 매개변수로 get 함수를 포함한 객체를 받는데, 이 get 함수를 통해 다른 atom, selector에 접근할 수 있다.
set은 데이터를 변화시키는 함수를 값으로 받을 수 있다.이 때 첫 번째 매개변수로 set 함수를 포함한 객체를 받고, 두 번째 매개변수로 입력된 새로운 값을 받는데, 이 set 함수를 통해 다른 atom의 값을 변화시킬 수 있다.
const tempFahrenheit = atom({ key: 'tempFahrenheit', default: 32, }); const tempCelcius = selector({ key: 'tempCelcius', get: ({get}) => ((get(tempFahrenheit) - 32) * 5) / 9, set: ({set}, newValue) => set( tempFahrenheit, newValue instanceof DefaultValue ? newValue : (newValue * 9) / 5 + 32, ), });
이런식으로 사용한다.
참고로 위 코드같이 동기적인 처리 뿐 만 아니라, get으로 비동기적인 처리도 할 수 있으나, 직접 해본적은 아직 없기에 링크로만 남겨두겠다.
2-1-1. get:
get: ({get}) => ((get(tempFahrenheit) - 32) * 5) / 9,
get 키 값은 함수를 값으로 받아야 한다.
이 때 받는 함수의 첫 번째 매개변수는 get 함수를 포함한 객체이다.
이 get 함수는 인자로 atom, 또는 selector을 전달해야 한다.
이 때, get으로 받은 recoil 상태로 조건문이나 filter을 걸어 결과에 따라 다르게 return 시키면 필터링 기능을 구현하게 되는 것이다.
2-1-2. set:
set: ({set}, newValue) => set( tempFahrenheit, newValue instanceof DefaultValue ? newValue : (newValue * 9) / 5 + 32, ),
set 키 값은 함수를 값으로 받아야 한다.
이 때 받는 함수의 첫 번째 매개변수는 set 함수를 포함한 객체이고, 두 번째 매개변수는 입력된 새로운 값이다.
두 번째 매개변수로 값을 전달하는 방법은 아래에 2-2-1에서 다룬다.
이 set 함수는 첫 번째 인자로 atom, 즉 recoil의 상태를 전달해야 하고, 두 번째 인자로 변화시킬 새로운 값을 전달해야 한다.
여기서 중요한 점은 두 번째 인자(newValue)인 새로운 값의 타입이다.
이 인자는 두 개의 타입 중 하나를 갖을 수 있는데,
첫 번째 경우는 위의 get 키로 받은 get 함수로 호출하는 atom, selector의 데이터 타입,
두 번째 경우는 DefaultValue이다.
만약 newValue가 useResetRecoilState()와 같이 selector를 재설정하는 인자가 들어오는 경우, newValue는 DefaultValue 클래스의 인스턴스이기 때문에, 이 때는 별도의 수정없이 newValue값을 그대로 전달해야 한다.
따라서 수정될 값을 set 함수의 두 번째 인자로 보내기 전에 newValue가 DefaultValue의 인스턴스인지를 검사하는 것이다.
2-2-1. useRecoilState()
const [tempC, setTempC] = useRecoilState(tempCelcius); const addTenCelcius = () => setTempC(tempC + 10);
selector도 atom과 마찬가지로 useRecoilState의 인자로 전달할 수 있다.
하지만 이렇게 selector를 사용할 경우 tempFahrenheit atom(실제 저장되는 데이터)을 1개만 가지고도 tempFahrenheit, tempCelcius 두 온도를 모두 보여주고, 변환 계산이 가능해진다.
recoil-persist - npm 페이지
recoil-persist는 recoil의 상태를 브라우저 Storage에 실시간으로 저장하고, 불러오게 해주는 라이브러리이다.
사용방법은 recoil atom함수로 전달하는 객체의 키 값으로 effect_UNSTABLE를 주고 값으로 전달되는 의존성 배열에 recoilPersist로 생성된 atomEffect를 넣어주면 된다.
const { persistAtom: persistCategory } = recoilPersist({ key: "categoryLocal", storage: localStorage, }); export const categoriesState = atom<ICategories[]>({ key: "categories", default: [ { title: "To Do", id: 0 }, { title: "Doing", id: 1 }, { title: "Done", id: 2 }, ], effects_UNSTABLE: [persistCategory], });
recoilPersist는 객체 하나를 인자로 받는데, 역시 사용해야 하는 키 값이 정해져 있다.
key, storage만 사용해봤다.
key는 recoil-persist 고유 식별자로, 문자열을 값으로 받는다.
storage는 브라우저 로컬 저장소의 위치를 지정한다. localStroage, localSession 등 지정할 수 있는데 localStorage만 사용해봤다.
기존에는 js로 길-게 쳐야했던 기능을 단 몇줄로 구현 가능하단 사실은 편하긴 했지만, 요근래 없데이트인 상태로 남아있기에...(포스트 작성일 기준, 최근 업데이트가 2달 전) 사용에 주의가 필요할 듯 하다.
요약
const tempFahrenheit = atom({ key: 'tempFahrenheit', default: 32, }); const tempCelcius = selector({ key: 'tempCelcius', get: ({get}) => ((get(tempFahrenheit) - 32) * 5) / 9, set: ({set}, newValue) => set( tempFahrenheit, newValue instanceof DefaultValue ? newValue : (newValue * 9) / 5 + 32, ), }); function TempCelcius() { const [tempF, setTempF] = useRecoilState(tempFahrenheit); const [tempC, setTempC] = useRecoilState(tempCelcius); const resetTemp = useResetRecoilState(tempCelcius); const addTenCelcius = () => setTempC(tempC + 10); const addTenFahrenheit = () => setTempF(tempF + 10); const reset = () => resetTemp(); ... }
'FW, Lib 공부 > React' 카테고리의 다른 글
styled-components (0) 2022.07.20 React 프로젝트 gh-pages 배포 (0) 2022.07.03 useRouteMatch() (0) 2022.06.22 useLocation() (0) 2022.06.22 useParams() (0) 2022.06.22