로그인/회원가입 모듈을 개발하다가 문득 위와같은 문제에 부딪혔다.
로그인/회원가입 실패시 모달을 띄워주고, 성공시 페이지 리다이렉트를 하는 모듈을 만들어야한다.
예를들어 로그인페이지(/login)에서, 로그인실패시에는 모달을 띄워주고, 성공시 홈('/')으로 간다고 가정해보자.
만약 '/login' path의 컴포넌트에 상태업데이트 스케쥴이 남아있을때, push를 통해 즉시 다른 path로 들어간다면 상태 업데이트 스케쥴을 통해 리렌더링이되야하는 컴포넌트(/login)가 사라져버릴것이다.
그렇게되면 위와같은 오류를 보게 될 것이다.
export const useUserAuth = (reqFunction,startWithPending,isLogin) => {
const history = useHistory();
const reduxDispatch = useDispatch();
const [state,dispatch] = useReducer(authReducer,{
status:startWithPending ? 'pending': null,
data : null,
error: null
});
const sendRequest = useCallback(async(reqParams)=>{
dispatch({type:'SEND'});
try{
const data = await reqFunction(reqParams,isLogin);
reduxDispatch({type:'LOGIN',payload:{idToken:data.idToken , expiresIn:data.expiresIn , dispatch:reduxDispatch} });
history.replace('/');
}catch(err){
dispatch({type:'ERROR',payload:err.message});
}
},[isLogin]);
Dispatch가 호출되어 reduxstore 데이터가 변경되면, login컴포넌트가 리렌더링된다.
맨 위의 질문에서처럼, 만약 push,replace가 동기적 실행이라면, dispatch에 의한 리렌더링 스케줄이 남아있는상태에서 redirect가 이뤄지기 때문에, 에러로그가 뜰것이다.
dispatch가 호출되고 history.replace가 호출된 후에, dispatch에 의한 리렌더링이 일어나고,
그다음 replace가 적용되는것을 콘솔로 확인하였다.
즉, history.replace가 호출되기전에 스케쥴된 것들을 모두 처리한다음 redirect가 발생한다.
1월11일 추가내용)
리액트에서 history API를 사용할때 보통 두가지 방식을 사용한다.
Redirect 컴포넌트는, 마운트 되었을 때 , history.push를 호출하도록 설계되어 있는것 같다.
history.push()를 호출한다고해서, 그 즉시, 해당 함수형 컴포넌트의 return문이 block 되는 것이 아니라, 마운트 된 다음, historyAPI가 동작한다. 따라서, 의도하지않은 의미없는 컴포넌트가 아주 순간적으로 렌더링이 되게되는데(눈에는 거의 보이지 않음), 이를 방지할 때 Redirect컴포넌트를 사용한다.
👇 참고 링크
https://stackoverflow.com/questions/48619733/react-router-redirect-vs-history-push
테스팅을 끝내고 혹시나해서 스택오버플로우를 봤는데 역시 비슷한 질문이 있었다.
https://stackoverflow.com/questions/53921508/is-history-push-an-async-call-in-react