ISSUE
이슈내용
- 컴포넌트 내, 핸들러 작성시 잘못된 dependecy 인한 state missmatch
Environment
- ComponentA 기준, core module의 Event를 subscribe하는 eventListener 코드 존재.
// 예제 코드
function ComponentA() {
/*
* @param {string} eventName
* @param {function} callback
* @param [React.DependencyList] dependencies
*/
useEventHandler("Events.Command.A", handler, [])
}ISSUE
핸들러 내부 코드는 외부 상태에 의존하는데 잘못된 dependency 기재로 stateA의 sync Miss Match가 발생
// 잘못된 코드
function ComponentA() {
const [b, setB] = useRecoilState(withB);
const [a, setA] = useRecoilState(withA);
const handler = (data) => {
if(!_.isEqual(data, a)){
setState(data);
}
}
useEventHandler('Events.Command.A', handler, [b]); // issue 잘못된 dependecy 기재
}
// useEventHandler는 b 상태에만 의존됨에 오직 b상태만 sync 보장.
// 우리가 요구하는 a 상태는 missMatch가 발생할 여지가 생김.Solution
solution 1 : Component의 dependency를 주지 않고, 전적으로 Component Rendering에 의존 → rerendering마다 handler를 생성함으로 비효율적으로 추천하지 않음.
solution 2 : 제공된 useEventHandler 함수의 올바른 dependency a 인자값 추가
solution 3 : recoil 내장 함수의 useRecoilCallback을 사용한다.
- 3.1 : solution 2와 동일하게 useRecoilCallback내 올바른 dependency a 인자값 추가
- 3.2 : useRecoilCallback내 파라미터를 살펴보면, set과 snapShot을 제공한다. 위 함수를 이용해 함수 호출 시점의 동기화 작업이 가능하다.
// 3.2 정상 동작
function ComponentA() {
// const [b, setB] = useRecoilState(withB);
// const [a, setA] = useRecoilState(withA);
const handler = useRecoilCallback(({set, snapshot}) => async (data) => {
const a = await snapshot.getPromise(setA);
if(!_.isEqual(data, a)){
// setState(data);
set(setA, data);
}
})
useEventHandler('Events.Command.A', handler);
}이점: callback 함수 내에서 state와 updater() 제공함으로 함수 밖에서 useRecoilState()를 변수들을 참조 안해도됨(dependency).
Feeling
React 내 발생하는 상태 이슈를 파악하고, 이를 해결할 수 있는 방안을 나열하였으며 효과적인 해결책을 찾아내었다.