이전 포스트에서 SPA 에 대해 다뤄보았다.
react 프로젝트에서 SPA를 쉽게 도입할 수 있도록 도와주는 라이브러리가 있는데,
바로 react-router 이다!
react 프로젝트에서 SPA를 쉽게 도입할 수 있도록 도와주는 라이브러리
설치 : $ npm i react-router
or $ npm i react-router-dom
react-router-dom 을 설치하는 이유 ? 브라우저에서 사용할 것이기 때문에
import { BrowserRouter, Route, Routes } from "react-router-dom";
const Hello = () => (
<Link to='/'>to home</Link>
);
const Main = () => (
<Link to='/hello'>to hello</Link>
);
const App = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Main />} />
<Route path="/hello" element={<Hello />} />
</Routes>
</BrowserRouter>
)
}
<Routes />
: 를 아래와 같이 동작하도록 만듦
<Route />
: props.path와 브라우저의 url이 일치하면 props.element를 return
가장 먼저 일치하는 Route 만 적용
<Link />
: props.to 에 적힌 url로 http get request를 보내지 않고
브라우저에 표시되는 url만 변경
path 에 동적인 값을 주기 위해서 가변 parameter의 앞에 콜론(:)를 붙이면
뒤 string 을 key로하는 parameter를 받을 수 있다.
import { BrowserRouter, Route, Routes, Link, useParams } from "react-router-dom";
// Hello 컴포넌트
const Hello = () => {
// 공식적인 react의 hook 아니고 react-router-dom 서 hook 처럼 만든 것
const params = useParams();
console.log(params); // Object { id: '5' }
return (
<Link to='/'>to home</Link>
);
}
// Main 컴포넌트
const Main = () => (
<Link to='/hello/5'>to hello with id 5</Link>
);
const App = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Main />} />
<Route path="/hello/:id" element={<Hello />} />
</Routes>
</BrowserRouter>
)
}
[:id]
, /:id?
: optional parameter
v6 로 넘어오면서 없을 경우를 대비하여 optional parameter 를 설정하기보단 없을 때의 component 를 만들어서 랜더를 하도록 하는 것을 권장한다.
2개 이상의 params 를 사용해야할 경우
아래처럼 path 를 구분하는 것보다
<Route path="/hello/:id:pw" element={<Hello />} />
search query 를 이용하는 것이 바람직하다.
<Route path="/hello" element={<Hello />} />
로 하고 이런 식으로 url 처리를 하고,
const Main = () => (
<Link to='/hello/?id=5&pw1234'>to hello with id 5</Link>
);
useLocation 의 serch 를 변수에 담아서 활용하는 것이 바람직하다.
지난번 실습 때 만든 회원가입 form 컴포넌트에서
회원가입 성공시 alert를 띄우는 대신
안녕하세요 {id}님! 이 적힌 페이지로 이동시키기
🔗 index.js
// react-router-dom 에서 BrowserRouter, Route, Routes 꺼내오기
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Hello from "./Router/Hello";
import UseRefEx from "./UseRefEx";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<BrowserRouter>
<Routes>
{/* React elememt 를 보여준다. */}
<Route path="/" element={<UseRefEx />} />
<Route path="/:id" element={<Hello />} />
=> id 값에 따라 동적으로 보여줄 컴포넌트
</Routes>
</BrowserRouter>
</React.StrictMode>
);
<Route path="/:id" element={<Hello />} />
=> id 값에 따라 동적으로 보여줄 컴포넌트
: parameter 를 통해 동적으로 path 값을 주어서 컴포넌트를 그리도록 셋팅
🔗 UseRefEx.js (로그인 폼 컴포넌트)
이전 코드에서 달라진 부분은
<Link to={`/${id}`}>
<button
type="button"
onClick={handleClick}
disabled={id.length < 1 && password.length < 1 && email.length < 1}
>
회원가입
</button>
</Link>
이때 Link 의 종착지는 path="/:id"
의 path 를 갖는 <Hello />
컴포넌트이다.회원가입이 완료되고 로그인창으로 넘어가지 않는 조건들일 때 button 의 submit 동작을 막는다. (id, pw, email 가 유요하지 않을 때)
const handleClick = (e) => {
if (!vaildId) {
e.preventDefault();
alert("유효하지 않은 id 입니다.");
setInputs({
...inputs,
id: "", // 바뀐 값 빼고 나머지는 그대로 스프레드 연산자
});
inutRef.current[0].focus();
} else if (!vaildPassword) {
e.preventDefault();
alert("유효하지 않은 password 입니다.");
inutRef.current[1].focus();
setInputs({
...inputs,
password: "",
});
} else if (!vaildEmail) {
e.preventDefault();
alert("유효하지 않은 email 입니다.");
inutRef.current[2].focus();
setInputs({
...inputs,
email: "",
});
}
};
각각 e.preventDefault()
를 해주었다!
이렇게 하면, 유효성 검사를 모두 통과했을 경우에만 Link 를 통해 컴포넌트 간 이동을 할 수 있다.
🔗 Hello.js (로그인/회원가입 완료 컴포넌트)
import { Link, useParams } from "react-router-dom";
export default function Hello() {
const { id } = useParams();
return (
<div>
<p>안녕하세요{id} 님! </p>
<Link to="/">
<button>로그아웃</button>
</Link>
</div>
);
}
usePrams 를 통해 받아온 데이터는 우리가 :id
에 작성한 id 라는 키에 값이 담겨져있다.
그렇기 때문에 비구조화할당을 통해 id 값을 받아오고, 해당 id 를 html 에 그려주면 완성!
또한, 로그아웃 버튼을 누르면 다시 회원가입 (로그인) 폼으로 돌아간다.