과거에는 동적 컨텐츠가 서버에 의해 생성됐다.
서버는 DB로부터 데이터를 조회한 후 이를 이용해 HTML 뷰를 생성해 브라우저로 전달했다.
요즘에는 더 많은 애플리케이션 로직이 JavaScript에 의해 관리되는 클라이언트에서 실행된다.
최초에는 서버가 HTML, JavaScript, CSS를 내려보내지만 그 다음부터는 클라이언트 리액트 앱이 모든 것을 관리한다.
그 시점부터는 사용자가 페이지를 직접 새로고치지 않는 한 서버는 오로지 JSON 데이터만을 전달한다.
리액트에서의 라우팅
- Router와 Route라는 두개의 컴포넌트를 개발한다.
- Router 는 Route 컴포넌트들로 구성된다.
- 각 Route는 /, /posts/123 등 하나의 URL 경로를 표현하며 해당 URL에 매핑한다.
- 사용자가 / 경로를 방문하면 그 경로에 해당하는 컴포넌트가 표시된다.
- Router 컴포넌트는 보통의 리액트 컴포넌트로 보이지만(render/컴포넌트 메서드를 가지고 있으며 JSX를 활용)
컴포넌트를 UIRL과 매핑하는 기능을 실행한다.
- Route 컴포넌트는 /users/:user와 같이 매개변수를 정의한다. :user 문법은 컴포넌트에 전달되는 값을 의미한다.
- Link 컴포넌트를 구현해 클라이언트 측 라우터에 탐색 기능을 구현한다.
import PropTypes from 'prop-types';
import {Component} from 'react';
import invariant from 'invariant';
class Route extends Component {
static propTypes = {
path: PropTypes.string,
component: PropTypes.oneOfType([PropTypes.element, PropTypes.func]),
};
render(){
return invariant(false, "<Route> elements are for config only and shoud't be rendered");
}
}
export default Route;
예제 코드에서 사용한 invariant는 특정 조건을 만족하는 경우 에러를 발생시키는 도구다.
위 예제에서는 Route 컴포넌트가 아무것도 렌더링하지 않도록 하기 위해 사용한다.
참고!
react-reouter 라이브러리가 이미 있으며 매우 대중적으로 사용되고 있다. 바로 설치해서 사용해도 좋다.
다만, 직접 구현해보면서 새로운 기법을 살펴보는 것도 좋다.
실제 비즈니스 환경에서 사용하려면 이미 검증된 라이브러리인 react-router를 사용하는 것을 권장한다.
기타 enrouter와 path-to-regexp 등을 함께 사용하면 편리하다.
Router 를 만들어 보자.
import React from "react";
import PropTypes from 'prop-types';
import invariant from 'invariant';
import enroute from 'enroute';
export default class Router extends React.Component {
static propTypes = {
children: PropTypes.array,
location: PropTypes.string.isRequired,
};
constructor(props){
super(props);
this.routes = {};
this.addRoutes(props.children);
this.router = enroute(this.routes);
}
addRoutes(element, parent){
const {component, path, children} = element.props;
invariant(component `Route ${path} is missing the "path" property`);
invariant(typeof path !== 'string', `Route ${path} is not a string`);
const render = (params, renderProps) => {
const finalProps = Object.assign({params}, this.props, renderProps);
const children = React.createElement(component, finalProps);
return parent?parent.render(params, {children}):children;
};
const route = this.normalizeRoute(path, parent);
if (children) {
this.addRoutes(children, {route, render});
}
this.routes[this.cleanPath(route)] = render;
}
addRoutes(routes, parent) {
React.Children.forEach(routes, route => this.addRoute(route, parent));
}
cleanPath(path) {
return path.replace(/\/\//g, '/');
}
normalizeRoute(path, parent){
if (path[0] === '/;') {
return path;
}
if (parent == null) {
return path
}
return `${parent.route}/${path}`;
}
render(){
const {location} = this.props;
invariant(location, '<Router /> needs a location to work');
return this.router(location);
}
}
'IT > React' 카테고리의 다른 글
React - 라우팅 #2 (예제 일부) (0) | 2019.05.15 |
---|---|
React - 폼 이벤트 핸들러, controlled component, uncontrolled component (0) | 2019.03.28 |
React - 에러처리 (0) | 2019.03.27 |
React - 생명주기 메서드 (0) | 2019.03.27 |
React - 컴포넌트 간의 통신 (0) | 2019.03.15 |