이 작업은 복잡하지 않아서 그냥 컴포넌트를 만들어서 그 안에 또 Route 컴포넌트를 렌더링하면 된다.
우선 src 에 Profiles 라는 컴포넌트를 만들어서, 그 안에 각 유저들의 프로필 링크들과 프로필 라우트를 함께 렌더링해겠다.
import React from 'react';
import { Link, Route, Routes } from 'react-router-dom';
import Profile from './Profile';
const Profiles = () => {
return (
<div>
<h3>유저 목록:</h3>
<ul>
<li>
<Link to="/profiles/velopert">velopert</Link>
</li>
<li>
<Link to="/profiles/gildong">gildong</Link>
</li>
</ul>
<Routes>
<Route path="/profiles" element={<div>유저를 선택해주세요.</div>}/>
<Route path="/profiles/:username" element={<Profile />} />
</Routes>
</div>
);
};
export default Profiles;
위 코드에서는 첫 번째 Route 컴포넌트에서 element 대신에 render 가 사용되었다.
여기서 컴포넌트가 아니라 JSX 자체를 렌더링 할 수 있다. JSX 를 렌더링하는 것이기에, 상위 영역에서 props 나 기타 값들을 필요하면 전달 해 줄 수 있다.
다음으로 App 에서 Profiles 를 위한 링크와 라우트를 생성해준다. (기존 Profiles 라우트는 제거해준다.)
import React from 'react';
import { Route, Link, Routes } from 'react-router-dom';
import About from './About';
import Home from './Home';
import Profiles from './Profiles';
const App = () => {
return (
<div>
<ul>
<li>
<Link to="/">홈</Link>
</li>
<li>
<Link to="/about">소개</Link>
</li>
<li>
<Link to="/profiles">프로필 목록</Link>
</li>
</ul>
<hr />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="*" element={<Profiles />} />
</Routes>
</div>
);
};
export default App;
velopert 를 클릭했을 때...
gildong 를 클릭했을 때...
잘 출력이되는걸 확인 할 수 있다.
이번에는 알아두면 유용한 리액트 라우터의 부가기능들을 알아보겠다.
history 객체는 라우트로 사용된 컴포넌트에게 match, location 과 함께 전달되는 props 중 하나이다. 이 객체를 통해서 우리가 컴포넌트 내에 구현하는 메소드에서 라우터에 직접 접근을 할 수 있다.
예 ) 뒤로가기, 특정 경로로 이동, 이탈 방지 등..
그런데 이 객체가 새로운 리액트 라우터에서는 사라져서 useNavigate 훅을 사용해야 한다.
useNavigate 은 useHistory의 기능을 전부 대체 가능하다
그리고 useHistory의 history는 객체였지만 useNavigate의 navigate는 함수다.
예 )
const navigate = useNavigate();
navigate('/');
navigate(-1);
navigate(-2);
navigate(`/user/${user._id}`);
src 디렉토리에 HistorySample.js 파일을 만들어주고 다음과 같이 코드를 작성해준다.
import React, { useEffect } from 'react';
import {useNavigate} from 'react-router-dom'
function HistorySample() {
const navigate = useNavigate();
const goBack = () => {
if(!window.confirm("정말로 떠나실건가요?")){
navigate(0);
}else{
navigate(-1);
}
};
const goHome = () => {
if(window.confirm("정말로 떠나실건가요?")){
navigate('/');
}else{
navigate(0);
}
};
useEffect(() => {
}, []);
return (
<div>
<button onClick={goBack}>뒤로가기</button>
<button onClick={goHome}>홈으로</button>
</div>
);
}
export default HistorySample;
그리고 App 에서 렌더링하고 버튼을 눌러보면...
import React from 'react';
import { Route, Link, Routes } from 'react-router-dom';
import About from './About';
import Home from './Home';
import Profiles from './Profiles';
import HistorySample from './HistorySample';
const App = () => {
return (
<div>
<ul>
<li>
<Link to="/">홈</Link>
</li>
<li>
<Link to="/about">소개</Link>
</li>
<li>
<Link to="/profiles">프로필 목록</Link>
</li>
<li>
<Link to="/history">예제</Link>
</li>
</ul>
<hr />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="*" element={<Profiles />} />
<Route path="/history" element={<HistorySample />} />
</Routes>
</div>
);
};
export default App;
useNavigate 을 사용해서 다른 곳으로 이동도 가능하고, 이탈시 메시지박스를 통하여 막을 수 도 있다.
사실 withRouter 를 사용해서 match / location / history 객체를 불러올려고 했는데 하필 리액트 라우터 버전이 6으로 바뀌면서 사라져버렸다.
그리하여 할 수 없이 useLocation 과 useParams 를 사용해서 textarea 태그에 정보들을 집어넣겠다.
useLocation
useParams
src 에 WithRouterSample.js 파일을 만들어주고 밑에 코드를 참고해라!
import React from 'react';
import { useLocation, useNavigate, useParams } from 'react-router-dom';
const WithRouterSample = () => {
const navigate = useNavigate();
const location = useLocation();
const params = useParams();
console.log(params)
return (
<div>
<h4>location</h4>
<textarea value={JSON.stringify(location, null, 2)} readOnly />
<h4>match</h4>
<textarea value={JSON.stringify(params, null, 2)} readOnly />
<button style={{display:"block"}} onClick={() => {navigate('/')}}>홈으로</button>
</div>
);
};
export default WithRouterSample;
그리고 이것을 Profiles.js 에 렌더링해준다.
import React from 'react';
import { Link, Route, Routes } from 'react-router-dom';
import Profile from './Profile';
import WithRouterSample from './WithRouterSample';
const Profiles = () => {
return (
<div>
<h3>유저 목록:</h3>
<ul>
<li>
<Link to="/profiles/velopert">velopert</Link>
</li>
<li>
<Link to="/profiles/gildong">gildong</Link>
</li>
</ul>
<Routes>
<Route path="/profiles" element={<div>유저를 선택해주세요.</div>}/>
<Route path="/profiles/:username" element={<Profile />} />
</Routes>
<Routes>
<Route path="/profiles/:username" element={<WithRouterSample />} />
</Routes>
</div>
);
};
export default Profiles;
velopert 를 클릭했을 때 이렇게 각 정보들을 확인할 수 있다.
NavLink 는 Link 랑 비슷한데, 만약 현재 경로와 Link 에서 사용하는 경로가 일치하는 경우 특정 스타일 혹은 클래스를 적용 할 수 있는 컴포넌트이다.
그러면 한번 Profiles 애서 사용하는 컴포넌트에서 Link 대신 NavLink 를 사용해보겠다.
import React from 'react';
import { Link, Route, Routes, NavLink } from 'react-router-dom';
import Profile from './Profile';
import WithRouterSample from './WithRouterSample';
const Profiles = () => {
return (
<div>
<h3>유저 목록:</h3>
<ul>
<li>
<NavLink to="/profiles/velopert" style={({ isActive }) => ({ color: isActive ? 'white' : 'rgb(85, 26, 139)', background: isActive ? 'black' : null })}>velopert</NavLink>
</li>
<li>
<NavLink to="/profiles/gildong" style={({ isActive }) => ({ color: isActive ? 'white' : 'rgb(85, 26, 139)', background: isActive ? 'black' : null })}>gildong</NavLink>
</li>
</ul>
<Routes>
<Route path="/profiles" element={<div>유저를 선택해주세요.</div>}/>
<Route path="/profiles/:username" element={<Profile />} />
</Routes>
<Routes>
<Route path="/profiles/:username" element={<WithRouterSample />} />
</Routes>
</div>
);
};
export default Profiles;
기존에 있던 activeStyle 대신 activeClassName 가 사라지면서 다음과 같이 삼항 조건 연산자 를 사용해서 클릭하면 글자에 검정색 배경과 하얀색 폰트로 바뀐다.
벨로퍼트에 있는 코드들은 버전 6 전이여서 아무리 구현해봐도 되지를 않는다.
무엇이 바뀌었는지 궁금하면 알아서 잘 찾아보자!
참고 : 벨로퍼트와 함께하는 모던 리액트
느낀점 :