React Router Dom을 사용하면 웹 앱에서 동적 라우팅을 구현할 수 있음
라우팅이 실행 중인 웹 외부의 구성에서 처리되는 기존 라우팅 아키텍처와 달리 React Router Dom은 앱 및 플랫폼의 요구 사항에 따라 컴포넌트 기반 라우팅을 용이하게 함
리액트는 SPA이기 때문에 하나의 index.html 템플릿 파일을 가지고 있음. 자바스크립트를 이용해서 다른 컴포넌트를 이 index.html 템플릿에 넣음으로써 페이지를 변경함. 이 때 React Router Dom 라이브러리가 새로운 컴포넌트로 라우팅/탐색을 하고 렌더링하는데 도움을 줌
설치 후 앱 어디에서나 React Router를 사용할 수 있도록 설정하려면 src 폴더에 있는 index.js 파일을 열고 react-router-dom에서 BrowserRouter를 가져온다음 루트 구성요소(App 구성 요소)를 그 안에 래핑하면 됨
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>
document.getElementById('root')
);
BrowserRouter
HTML5 Histroy API(pushState, replaceState 및 popstate 이벤트)를 사용하여 UI를 URL과 동기화된 상로 유지해줌
function App(){
return (
<div className="App">
<Routes>
<Route path="/" elements={<Home />} /> // https://localhost:3000/
<Route path="about" elements={<About />} /> // https://localhost:3000/about
<Route path="contact" elements={<Contact />} /> // https://localhost:3000/contact
</Routes>
</div>
)
}
Routes
Routes는 앱에서 생성될 모든 개별 경로에 대한 컨테이너/상위 역할
Route로 생성된 자식 컴포넌트 중에서 매칭되는 첫번째 Route를 렌더링 해줌
Route
Route는 단일 경로를 만드는 데 사용함. 두가지 속성을 가짐
- path: 원하는 컴포넌트의 URL 경로를 지정. 이 경로 이름을 원하는 대로 정할 수 있음
경로 이름이 '/'인 컴포넌트는 앱이 처음 로드될 때마다 먼저 랜더링됨
-> Home 구성 요소가 맨 처음으로 렌더링됨- element: 경로에 맞게 렌더링되어야 하는 컴포넌트를 지정
import { Link } from 'react-router-dom';
function Home() {
return (
<div>
<h1>홈페이지</h1>
<Link to="about">About 페이지를 보여주기</Link>
<Link to="contact">Contact 페이지를 보여주기</Link>
</div>
);
}
export default Home;
Link 구성 요소는 HTML의 앵커 요소 <a />와 유사함. to 속성으로 링크가 이동할 경로를 지정함
중첩 라우팅은 React Router의 가장 강력한 기능 중 하나
복잡한 레이아웃 코드를 좀 더 간결하게 해결해줌
대부분의 레이아웃은 URL의 세그먼트에 연결되며 React Router는 이를 완전히 수용
<BrowserRouter>
<Routes>
// App 컴포넌트에 Header나 Footer 등의 Layout
<Route path="/" element={<App />}>
// localhost:3000/ => Home 컴포넌트 렌더링
<Route index element={<Home />} />
// localhost:3000/teams => Teams 컴포넌트가 Layout
<Route path="teams" element={<Teams />}>
// localhost:3000/teams/13 => Team 컴포넌트
<Route path=":teamId" element={<Team />} />
<Route path="new" element={<NewTeamForm />} />
// localhost:3000/teams => LeagueStandings 컴포넌트 렌더링
<Route index element={<LeagueStandings />} />
</Route>
</Route>
</Routes>
</BrowserRouter>
자식 경로 요소를 렌더링하려면 부모 경로 요소에서 <Outlet />을 사용해야 함. 이렇게 하면 하위 경로가 렌더링될 때 중첩된 UI가 표시될 수 있음. 부모 라우트가 정확히 일치하면 자식 인덱스 라우트를 렌더링하거나 인덱스 라우트가 없으면 아무것도 렌더링 하지 않음
경로를 바꿔줌. ex) navigate('/home') ===> localhost:3000/home
:style 문법을 path 경로에 사용하였다면 useParams()로 읽을 수 있음
function App() {
return (
<Routes>
<Route path="invoices/:invoiceId" element={<Invoice />} />
</Routes>
);
}
function Invoice(){
let params = useParams();
return <h1>Invoice {params.invoiceId}</h1>;
}
이 Hooks는 현재 위치의 객체를 반환. 현재 위치가 변경될 때 마다 일부 side effect를 수행하려는 경우에 유용
useRoutes Hooks는 <Routes>와 기능적으로 동일하지만 <Route> 요소 대신 JavaScript 객체를 사용하여 경로를 정의함
이러한 객체는 일반 <Route> 요소와 동일한 속성을 갖지만 JSX가 필요하지 않음
원래는 입력창에 입력한 값이 onChange를 이용하면 바로 화면에 적용됨
하지만 debounce function을 이용하면 미리 결정해 놓은 시간 동안 타이핑을 멈출 때까지 keyup 이벤트의 처리를 지연시킴
입력된 모든 문자를 처리하면 성능이 저하되고 밴엔드에 불필요한 로드가 추가될 수 있음. 하지만 debounce를 이용하면 UI 코드가 모든 이벤트를 처리할 필요가 없고 서버로 전송되는 API 호출 수도 크게 줄어듬
모달창 바깥을 클릭했을 때 모달창이 닫히도록 만들기 -> 어디를 클릭했는지 구분해주어야 함 -> useRef
state를 사용하면 state가 변할때 컴포넌트가 다시 렌더링 되지만 ref를 사용하면 리 렌더링이 되지 않음 (생명주기 동안 ref 값은 유지됨)
보통 JavaScript에서는 getElementById나 querySelector 같은 DOM Selector 함수를 사용해서 특정 DOM 선택
리액트에서는 ref를 이용해서 DOM을 선택함
useRef()를 이용해 Ref 객체를 만들고, 이 객체를 특정 DOM에 ref 값으로 설정. 이렇게 되면 Ref 객체의 .current 값이 특정 DOM을 가리키게 됨
구조가 복잡하게 짜여있는 경우 Modal 요소 부분이 DOM 계층 구조에서 z-index 등의 영향을 받아서 맨 앞으로 가지 못하거나 원하는 모달 스타일을 가지지 못할 수가 있음
Portal은 부모 컴포넌트의 DOM 계층 구조 바깥에 있는 DOM 노드로 자식을 렌더링하는 최고의 방법을 제공
Portal의 특징 중 하나는 이벤트 버블링이 가능하다는 것
이벤트 버블링이란 중첩된 자식 요소에서 이벤트가 발생할 때 그 이벤트가 부모로 전달되는 것
비록 포탈로 생성한 부분이 부모 DOM 밖에 생성되더라도 DOM 트리에서의 위치에 상관없이 portal은 여전히 React 트리에 존재. 따라서 React 트리에 포함된 상위로 이벤트 버블링이 가능함