스토어의 상태값 여부를 검사하여 상태값이 없으면 다른 라우터로 이동하는 로직을 상위 컴포넌트에 추가하였다.
const InfoChecker = ({children}) => {
const {info} = useExampleStore()
const history = useHistory()
if (!info) {
history.replace('/')
return null
}
return children
}
const Info = () => {
const {info, clearInfo} = useExampleStore()
useEffect(() => {
return () => {
clearInfo()
}
}, [])
return (
<div>{info.name}</div>
)
}
const Routes = () => {
const {info} = useExampleStore()
return (
<InfoChecker>
<Route exact path={'/'} render={() => <Home />} />
<Route exact path={'/name'} render={() => <Info />} />
<Redirect to={'/'} />
</InfoChecker>
)
}
이 때 아래처럼 Warning을 받게 된다.
Warning: setState(...): Cannot update during an existing state transition (such as within render or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to componentWillMount.
Render 메서드 내부에 state를 변경하지 말라는 Warning이었다. Render내부에서 state를 바꾸면 모든 setState에 대해 컴포넌트가 다시 렌더링되므로 무한 루프가 발생하므로 권장하지 않는다.
그런데 위 코드에서는 state를 아래처럼 렌더링 도중에 바꾸는 코드가 없다.
const Example = () => {
const [isShow, setIsShow] = setState(false)
const toggle = () => setIsShow(prev => !prev)
return (
<>
<button onClick={toggle()}>toggle</button>
</>
)
}
크롬 디버거로 추적해보면 history.replace('/') 에서 Warning이 발생하고 있었다.
react-router가 페이지 이동을 할 때 props를 변경시키기 때문 + history는 mutable하므로 history.push(replace)는 컴포넌트의 props의 변경을 감지하고 리렌더링을 진행하므로 위와 같은 상황이 되버려 Warning이 발생하고 있는 것이었다.
출처. Why we should not have browserHistory.push('/some-path') in render() method ?
React runs by checking if props have changed, then re-renders. React Router changes the page through props. If you changed the state inside your render, the component would be caught in an infinite loop (rendering, updating the state, re-rendering, updating, etc etc).
출처. reactrouter.com
history is mutable
The history object is mutable. Therefore it is recommended to access thelocationfrom the render props of <Route>, not from history.location. This ensures your assumptions about React are correct in lifecycle hooks.
따라서 아래처럼 Redirect를 리턴하여 다른 페이지를 navigating하도록 한다.
const InfoChecker = ({children}) => {
const {info} = useExampleStore()
const history = useHistory()
if (!info) {
return <Redirect to={'/'} />
}
return children
}
'Today I Learn > 이슈 해결' 카테고리의 다른 글
react 16.8 -> 16.9 업그레이드로 인한 react-testing-library 실패 해결 (0) | 2021.10.05 |
---|---|
[Nextjs] 리액트에서 Nextjs로 이전하던 중 생긴 이슈들 (0) | 2021.07.28 |
[React] history.block으로 뒤로가기 막기 (blocking-transition) (0) | 2021.07.08 |
getEventListeners로 등록된 이벤트리스너 확인하기 (0) | 2021.06.14 |
[JS] Blur 이벤트 전에 Click 이벤트를 실행하기 (0) | 2021.03.17 |