리액트 라우터가 왜 필요하는가? 라는 질문의 답은 바로 SPA이다.
SPA (Single Page Application)은 페이지가 1개인 애플리케이션을 말한다.
즉 , 오직 하나의 html을 쓴다는 뜻인데 웹페이지가 1개인 애플리케이션안에서
다른 여러개의 페이지를 보여주는 방법이 바로 Routing이다.
Router의 사전적의미로는 서로 다른 네트워크를 연결해주는 장치이다.
Routing은 다른 url주소에 따라 다른 화면을 보여주는 것이다.
하지만 리액트는 library이기 때문에 이기능을 가지고 있지 않다.
우리는 Routing을 사용하기 위해서는 react-router를 설치하여야 한다.
리액트 라우터를 설치하는 방법은 Node.js를 통해
npm install react-router-dom --save
이 한문장이면 설치가 완료된다.
맨처음 기존에 있던 APP.js 를 삭제하고 Routes.js파일을 새로 생성하였다.
첫줄은 기존에 React에서 import한 것이고 두번째이 라우터를 import한 것이다.
{}안의 BrowserRouter는 history API를 사용해 URL과 UI를 동기화하는 라우터이다.
as를 사용하여 컴포넌트 안에서는 Router로 사용한다는 뜻이다.
그 외 Switch, Route는 아래 설명 참조
예시에서는 class 형태의 컴포넌트로 Routes 컴포넌트를 생성했다.
Router는 이곳에 경로가 있다는것을 의미한다.
Route 는 요청받은 pathname에 해당하는 컴포넌트를 렌더링한다.
path는 경로의 값을 지정할 때 사용한다.
여기서 " / "
는 home 화면을 의미한다.
component에는 랜더링할 컴포넌트를 기입한다.
exact가 있으면 주어진 경로와 정확히 맞아 떨어져야만 설정한 컴포넌트를 보여준다.
만약 exact가 없다면 홈화면에서도 "/main"
화면이 출력된다.
이유는 "/main"
에도 /
이 있기 때문에 매칭되어 보여지는 것이다.
Switch
<Router>
<Route exact path="/" component={Home} />
<Route path="/movies" component={Movies} />
<Route path="/reviews" component={Reviews} />
<Route component={PageNotFound} />
</Router>
만약 path에서 지정한 url 이외의 url이 들어왔을 때 즉, 에러가 발생했을 때
<PageNotFound>
컴포넌트를 보여주고 싶은데, 실제로 실행하면 어떤 url이 들어와도
<PageNotFound>
이 렌더링 된다.
리액트의 라우터가 path를 매칭시킬 값이 없기 때문에 무조건적으로 렌더링 시켜버린다.
이 문제를 해결하기위해 Switch를 사용한다.
switch는 첫번째로 매칭되는 path를 가진 컴포넌트를 렌더링한다.
<Router>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/movies" component={Movies} />
<Route path="/reviews" component={Reviews} />
<Route component={PageNotFound} />
</Switch>
</Router>
다음과 같이 switch로 감싸게 되면 에러가 발생하거나 알수없는 url을 입력받았을 때
<PageNotFound>
이 렌더링 된다. 위에서부터 첫번째로 매칭되는 path값이 없었기 때문이다.
import React from "react";
import ReactDOM from "react-dom";
import Routes from "./Routes";
ReactDOM.render(<Routes />, document.getElementById("root"));
index.js는 다음과 같이 작성하였다.
기존 APP.js가 있던자리에 Routes를 넣어주었다.
Route 이동하는 방법은 두 가지가 있다.
import React from "react";
import { Link, withRouter } from "react-router-dom";
import "./Login.scss";
class Login extends React.Component {
goToMain = () => {
this.props.history.push("/main");
};
render() {
return (
<div className="login">
<div className="login-wrapper">
<h1>westargram</h1>
<main>
<div className="login-input">
<input
id="js__input-id"
type="text"
placeholder="전화번호,사용자 이름 또는 이메일"
/>
<input
id="js__input-password"
type="password"
placeholder="비밀번호"
/>
</div>
<button className="login-button" onClick={this.goToMain}>
<span>로그인</span>
</button>
</main>
<footer className="login-footer">
<Link to="/">비밀번호를 잊으셨나요?</Link>
</footer>
</div>
</div>
);
}
}
export default withRouter(Login)
위의 코드는 Link, withRouter 모두 사용하였다.
Link
로그인 페이지에 비밀번호를 잊으셨나요?
문구는 원래 a태그와 herf속성을 사용하였으나
리액트 내에서 컴포넌트를 이동시킬 태그는 Link태그이다.
먼저 import { Link, withRouter } from "react-router-dom";
위에서
Link를 import를 해주고 사용할 때에는 Link to= 를 사용하여 이동할 컴포넌트를 지정한다.
withRouter
나는 버튼 태그를 클릭하게 되면 다른 컴포넌트로 이동하게 끔 만들고 싶었고
버튼태그에 link태그를 주었더니 아무 변화가 없었다.
이럴때에는 버튼에 우선 onClick 이벤트를 주고 다음과 같이 이벤트 핸들러를 지정한다.
<button className="login-button" onClick={this.goToMain}>
goToMain은 arrow 함수를 사용하여 this.props.history.push('/main');
를 실행시킨다.
props 객체의 history에 접근해서 이동하는 코드이다.
받은 history
의 push
메서드의 인자로 Routes.js
에서 설정한 path를 넘겨주면, 해당 라우트로 이동할 수 있다.
이 컴포넌트(Login 컴포넌트)에서 props에 route 정보(history)를 받으려면 export하는 컴포넌트에 withRouter로 감싸주어야 한다.
export default withRouter(Login)
Link태그는 단순히 클릭시 다른경로로 이동하거나 할때 사용
withRouterHOC는 페이지 전환 시 추가로 처리해야 하는 로직이 있는 경우 withRouterHOC 방법으로 구현