-
새로 알게 된 react-router 관련 토막 상식 (Query parameter가 바뀔 때마다 re-render 시키는 법)Frontend 2020. 12. 13. 21:54
import { ExampleComponent } from './example'; // ... <Route path='/example' component={ ExampleComponent } />
회사에서 react-router를 쓰면서 주로 위와 같은 방식으로 routing을 하다가
router v5 버전부터 아래와 같이 Route 컴포넌트 안에 child 컴포넌트를 합성하는 방식이 더 권장되는 것을 발견하고 바꾸었다.
import { ExampleComponent } from './example'; // ... <Route path='/example'> <ExampleComponent /> </Route>
근데 이걸로 바꾸는 순간 한 가지 이슈가 발생했는데... 😨
바로 이 이슈였다. 탭을 이동할 때마다 주소 뒤에 query parameter가 바뀌고,
이 query parameter가 바뀔 때마다 UI가 바뀌는 화면이 있었는데,
Routing 방식을 바꾸니까 갑자기 탭을 아무리 클릭해도 화면이 안 바뀌는 것이었다(!)
그래서 살펴보니, query parameter가 바뀌어도 컴포넌트가 re-render가 안되는 것이 문제였다.
그러니까 URL path 자체는 동일하고 뒤에 query parameter만 바뀌었기 때문인 것으로 추정된다.
<Route path='/example'> { () => <ExampleComponent /> } </Route> <Route path='/example' component={ ExampleComponent } /> <Route path='/example' render={ () => <ExampleComponent /> } />
즉, query paramter value가 바뀌어서 location 객체가 업데이트될 때마다 re-render를 하고 싶으면 위와 같이 사용을 해주어야만 했다.
Component
<Route path='/example' component={ ExampleComponent } />
우리가 Route의 component 속성을 사용하면, router는 React.createElement 메소드를 통해서 새로운 리액트 엘리먼트를 생성한다. 이 말은 만약에 component에 inline function을 넣어버리면 render를 할 때마다 새 컴포넌트를 매번 만들어낸다. 따라서 이미 존재하는 컴포넌트를 업데이트하는 것이 아니라 매 번 새 컴포넌트 mount, unmount를 반복하는 것이다. 그래서 만약에 inline function을 사용하고 싶으면 render 속성을 사용하는 것이 좋다.
Render
<Route path='/example' render={ (routerProps) => <ExampleComponent { ...routerProps } /> } />
render 속성을 사용하면 위에서 언급한 문제없이 inline function을 사용할 수 있게 된다. 그리고 편하게 routerProps를 새 컴포넌트에 주입해줄 수도 있다.
그렇다면, 위와 같이 component, render 속성을 이용하지 않고,
Route 컴포넌트 안에 children으로 컴포넌트를 사용하면서도
query parameter가 바뀌었을때 re-render가 일어나도록 하는 방법은 없는 것일까?
댓츠노노! 그렇지 않다.
react-router 라이브러리에서 제공하는 useLocation hook을 사용하면 가능하다.
그러니까 query parameter를 window.location 객체에서 가져다쓰는 것이 아니라,
useLocation() hook을 통해 가져와서 쓰면, query parameter가 바뀔 때마다 location hook을 사용하는 컴포넌트가 re-render된다.
import { useLocation } from 'react-router-dom'; import { parse } from 'query-string'; function ExampleComponent () { const { exampleQuery } = parse(useLocation().search); //... }
이 방법이 사실 더 좋은 이유는 component나 render 속성을 쓰면,
query parameter가 바뀔때마다 지정해준 컴포넌트의 하위 컴포넌트들이 모두 re-render가 된다.
그러다 그냥 <Route><ExampleComponent /></Route> 요렇게 사용하고
필요한 곳에서만 useLocation hook을 사용하면, 이 hook을 사용하는 곳에서만 re-render가 일어난다!
반응형'Frontend' 카테고리의 다른 글
[Kent C. Dodds] 어플리케이션 상태 관리 (Application State Management with React 한글 번역) (254) 2021.05.09 location.href vs location.assign vs location.replace 차이점 (254) 2021.05.09 페이스북에서 만든 React 상태 관리 라이브러리, Recoil.js (252) 2020.12.13 JavaScript, 숫자 타입이 아닌 값을 숫자로 바꾸는 다양한 방법 - feat. Number()/parseInt/Unary plus(+)/Unary negation(-) (127) 2020.11.08 [Kent C. dodds - Epic React] Advanced React Hooks(1) - useReducer 이해하기 (252) 2020.11.08 COMMENT