여태까지의 방법으론 localhost:3000/about
과 같이 한 단계를 진입하는데는 문제가 없었다. 하지만 요즘 URL
들이 워낙 복잡한건 다들 알고 있을 것이다. localhost:3000/about
만 해도 localhost:3000/about/policy
localhost:3000/about/contact
등등 여러 URL
로 나뉘어 있는 경우도 파다하다.
서브 라우트는 이럴때 사용하고, 라우트 내부에 또 라우트를 정의하는 것을 말한다.
지난 시간에 정의했던 User
를 다시 가져와보자.
import React from 'react';
import qs from 'qs';
const users = {
pkbird: {
name: '비빔면',
age: 25,
},
fahrenheit: {
name: '화씨',
age: 12,
},
};
const User = ({ match, location }) => {
const { userid } = match.params;
const queryData = qs.parse(location.search, { ignoreQueryPrefix: true });
console.log(queryData);
const user = users[userid];
if (!user) return null;
return (
<div>
<b>{user.name}</b> ({user.age}살)
</div>
);
};
export default User;
URL
에 따라 자신에게 오는 URL 파라미터와 쿼리
를 처리하고 유저이름과 나이를 출력하는 컴포넌트이다.
Users.js
파일을 만들고 다음같이 적어본다.
import React from 'react';
import { Link, Route } from 'react-router-dom';
import User from './User';
const Users = () => {
return (
<div>
<h3>유저</h3>
<ul>
<li>
<Link to="/users/pkbird">pkbird</Link>
</li>
<li>
<Link to="/users/fahrenheit">fahrenheit</Link>
</li>
</ul>
<Route path="/users" exact render={() => <div>유저를 선택하세요.</div>} />
<Route path="/users/:userid" component={User} />
</div>
);
};
export default Users;
이런식으로 직접 유저의 아이디를 URL 파라미터
로 입력해주지 않아도, Link
를 통해, 유저의 정보를 불러올 수 있도록 했다.
그 후 App.js
를 다음처럼 바꾼다.
import React from 'react';
import About from './About';
import Home from './Home';
import { Route, Link } from 'react-router-dom';
import Users from './Users'; // 바뀐 부분
function App() {
return (
<div>
<ul>
<li>
<Link to="/">홈</Link>
</li>
<li>
<Link to="/about">어바웃</Link>
</li>
<li>
<Link to="/users">조회</Link> // 바뀐 부분
</li>
</ul>
<Route path="/" component={Home} exact />
<Route path={['/about', '/hi']} component={About} />
<Route path="/users" component={Users} /> // 바뀐 부분
</div>
);
}
export default App;
이렇게 Users
컴포넌트로 라우팅을 시키면, 조회링크를 클릭할 시, 아래처럼 화면이 나온다.
pkbird
와 fahrenheit
링크는 users/pkbird
users/fahrenheit
로 라우트로 사용되고 있는 Users
컴포넌트 안에 또다시 Route
를 정의하여, 깊숙히 들어갈 수 있게한다.
<Route path="/users" exact render={() => <div>유저를 선택하세요.</div>} />
<Route path="/users/:userid" component={User} />
이렇게하면 users
만 입력하면 유저를 입력하란 글귀가 뜨고,
users/유저아이디
즉 저 링크 중 하날 클릭하면 URL 파라미터
가 User
컴포넌트에 전해지게 되고 그럼 링크마다 결과값인 유저이름과 나이가 다르게 보인다.
요약을 하면, 라우트로 사용되는 특정 컴포넌트 (위 경우는
Users
)안에 또 다른 라우트를 사용할 때, 그것을 서브 라우트라고 부른다. 이렇게하면User
컴포넌트는서브 라우트
가 되고 라우트의URL 파라미터
를 사용할 수 있게 된다.
history
객체는 라우트로 사용된 컴포넌트에 match, location
과 함께 전달되는 props
이다. 이 객체를 잘 사용하면 라우터 API
를 호출할 수 있다.
그게 뭔데 X덕아
예를 들어, 로그인 후 화면 전환, 버튼 클릭시 뒤로 가기, 다른 페이지 이탈 방지 등에 활용한다.
history.goBack()
은 뒤로 가기 이다.
history.push('/')
는'/'
주소로 라우트 한다.
history.block(message)
는 페이지에 변화가 생기는 것을 캐치해 유저에게 질문을 던진다.
User
컴포넌트에서 렌더 작성하는 파트에 다음과 같이 적어본다.
<div>
<b>{user.name}</b> ({user.age}살)
<button onClick={() => history.goBack()}>뒤로 가기</button>
</div>
버튼을 추가해보는 것이다.
그럼 다음과 같이 뒤로 가기 버튼이 생기고 클릭하면
나는 Users
컴포넌트에서 눌렀기 때문에 /users
로 되돌아가는 걸 볼 수 있다.
<button onClick={() => history.push('/')}>홈으로</button>
뒤로 가기 버튼 밑에 다음같이 코드를 한 줄 더 추가해보자
그럼 홈으로
라는 글귀의 버튼이 생긴걸 알 수 있는데 클릭해보면,
홈으로 돌아가는 걸 볼 수 있다.
이런식으로 history
를 활용해 뒤로가거나, 홈으로 가거나 등등을 조작할 수 있다.
위에서도 썼듯이 로그인이 되면 history.push를 통해 홈으로 가거나, block을 통해 현재 웹페이지에서 벗어나는 것을 막기 위한 경고 메시지 등을 띄워줄 수 있다.
이번에 쓰일 withRouter
는 은근히 앞으로 리액트 공부를 하면서 알게모르게 많이 보게 되는 녀석이다. 그래서 바짝 긴장... 까진 할 필요는 없지만 아무튼 잘 새겨서 보면 좋을 것 같다.
withRouter
는 HoC
인데, 이게 뭐냐면 Higher-order Component
의 약자이다.
라우트로 사용된 컴포넌트가 아닌데도, match, location, history
객체에 접근하게 해준다.
구현법은 단순하다.
import React from 'react';
import { withRouter } from 'react-router-dom';
const WithRouterSample = ({match, location, history}) => {
return (
<div>
</div>
);
};
export default withRouter(WithRouterSample);
이렇게 맨끝에 withRouter()
추가해 컴포넌트를 감싸주면 된다.
이렇게만 해주면 해당 컴포넌트는 라우트로 사용되지 않는데도 불구하고 match, location, history
를 다룰 수 있게 된다. 라우트로 사용되는 다른 컴포넌트
에 같이 렌더링을 해서 이것저것 출력해보면 진짜로 그 라우트로 넘어간 댜앙한 객체들을 사용할 수 있게 된다.
하지만, 여기서 주의할 점이 한 가지 있다.
자신을 보여주고 있는 라우트 컴포넌트를 기준으로
match
를 받는다.
이게 무슨 말이냐면, Users
컴포넌트에 이 withRouter
컴포넌트를 렌더링시키게 되면, Users
컴포넌트의 match
에는 유저에 대한 정보가 없기 때문에, params
가 출력되지 않는다.
반면에, User
컴포넌트에 넣게되면, /users/pkbird
처럼 유저 아이디라는 params
를 받아오기 때문에, params
가 출력된다. 따라서 withRouter
를 쓸 경우, 어디에 넣어야 params
를 제대로 받아올 수 있는지에 대한 고민을 꼭 해봐야 한다.
Users
에 넣든 User
에 넣든 화면에 그 컴포넌트가 렌더링 되는건 매 한가지지만, params
를 받아올 수 있느냐 없느냐는 큰 차이가 있다.
쓰고보니 너무 대충 쓴거 같은데.. 사실 길게 다루고 자시고 할 게 없긴 하다.
나중에 좀 실제로 어떤식으로 사용하는지 다룰 시간이 있으면 좋을것 같은데 장담은 못하겠네.
여러 Route를 감싸서, 그중 일치하는 하나의 라우트만 렌더링 시켜준다.
이건 왜 쓰냐하면, Not Found
에 대한 처리를 하기 위해서 주로 쓰인다.
예를 들어, users/pkbird
이런건 라우트가 잘 되어있다. 올바르게 동작한다.
하지만 쌩뚱맞게 id/hihihi
이런 URL
을 넣게되면 여기에는 아무런 정보도 들어있지 않다.
그런데도 불구하고, 위처럼 홈, 어바웃, 조회를 출력한다.
왜냐면, 저건 라우트가 아니고 링크로 적혀있는거기 때문에 URL
과 상관없이 출력된다.
<li>
<Link to="/">홈</Link>
</li>
<li>
<Link to="/about">어바웃</Link>
</li>
<li>
<Link to="/users">조회</Link>
</li>
하지만, 나는 화면에 너가 지금 잘못된 주소로 들어왔다는 걸 보여주고 싶다.
그럴때는, Switch
로 Route
들을 감싸고, 다음과 같이 처리한다.
<Switch>
<Route path="/" component={Home} exact />
<Route path={['/about', 'hi']} component={About} />
<Route path="/users" component={Users} />
<Route
render={({ location }) => (
<div>
<h2>Not Found 404</h2>
<p>{location.pathname}</p>
</div>
)}
/>
</Switch>
이미 들어가있는 /, /about, /hi, /users
를 뺀 나머지를 URL
로 입력할 경우, 전부 다음과 같이 출력된다.
위에 링크들마저 안뜨게 하려면, 다른 조치가 필요해보이지만.. 귀찮으니 알아보진 않겠다.
여기까지 라우트의 거의 모든 것을 다뤄봤다.
그럼 끄읕~