ContextProvider를 사용할때 Route에는 어떻게 적용하는게 효율적일지!

<Route path="/app/dashboard">
  <DashboardContext>
    <Dashboard></Dashboard>
  </DashboardContext>
</Route>

반복적으로 위와같이 입력하기 어려우니 ContextRoute를 생성하자


import React from 'react';
import { Route } from 'react-router-dom';

const ContextRoute = ({ provider, component, ...rest }) => {
  const { Provider } = provider;
  const Component = component;

  return (
    <Route {...rest}>
      <Provider>
        <Component />
      </Provider>
    </Route>
  );
};

export default ContextRoute; 

위에 ContextRoute를 정의한 이후에는 다음과같이 작성하면 된다.

<ContextRoute
  path="/app/dashboard"
  provider={DashboardContext}
component={Dashboard}
/>

참고

  • 여러개의 Router를 생성하게 될텐데, 이렇게 되면 유지보수가 이후에는 어려워질수 있으니 router 모듈화를 진행
  • src/api/index.js 에 api에 관련된 호출을 나열

src/index.js

const Koa = require('koa');
const Router = require('koa-router');

const api = require('./api');

const app = new Koa();
const router = new Router();

// 라우터 설정
router.use('/api', api.routes()); // add api router

// app instance에 라우터 적용
app.use(router.routes()).use(router.allowedMethods());

app.listen(4000, () => {
  console.log('Listening to port 4000');
});

src/api/index.js

const Router = require('koa-router');
const api = new Router();

api.get('/test', ctx => {
  ctx.body = 'test 성공';
});

module.exports = api;
  • src/api/index.js를 생성하고, src/index.jsrouter.use를 통해 router를 등록해주면 된다.
  • 이때 주의해야할점은 src/api/index.js에서 반드시 exports를 해줘야 한다.

posts API 생성하기

  • src/api/posts/index.js에 아래와 같이 posts에 관련된 api의 목록들을 정의한다.
  • 정의한 route를 src/api/index.js에 적용을 해주면 된다.

src/api/index.js

const Router = require('koa-router');
const posts = require('./posts');

const api = new Router();

api.use('/posts', posts.routes());

module.exports = api;

src/api/posts/index.js

const Router = require('koa-router');
const posts = new Router();

const printInfo = ctx => {
  ctx.body = {
    method: ctx.method,
    path: ctx.path,
    params: ctx.params,
  };
};

posts.get('/', printInfo);
posts.post('/', printInfo);
posts.get('/:id', printInfo);
posts.delete('/:id', printInfo);
posts.put('/:id', printInfo);
posts.patch('/:id', printInfo);

module.exports = posts;
  • 위 같이 정의하고 http://localhost:4000/api/posts/12을 호출하면 아래와 같은 결과가 나온다.

$ yarn add koa-router
const Koa = require('koa');
const Router = require('koa-router');

const app = new Koa();
const router = new Router();

// 라우터 설정
router.get('/', ctx => {
  ctx.body = '홈';
});
router.get('/about', ctx => {
  ctx.body = '소개';
});

// app instance에 라우터 적용
app.use(router.routes()).use(router.allowedMethods());

app.listen(4000, () => {
  console.log('Listening to port 4000');
});

Router Parameter, Query

  • /about/:name의 형식으로 :을 사용하여 라우트 경로 설정
  • ctx.params의 객체에서 조회
  • /posts/?id=10 처럼 조회하면 ctx.query에서 조회
    • 문자열 형태는 ctx.querystring
router.get('/about/:name?', ctx => {
  const { name } = ctx.params;
  ctx.body = name ? `${name}의 소개` : '소개';
});

router.get('/posts', ctx => {
  const { id } = ctx.query;
  ctx.body = id ? `포스트 #${id}` : `포스트 없어`;
});
  • http://localhost:4000/about/icecream
  • http://localhost:4000/posts?id=10

여러개의 메뉴가 있다고 가정해보자. 그 메뉴에서 내가 선택한 메뉴에 특정 스타일을 주고싶다.
사용자는 UI에서 내가 선택한 메뉴가 무엇인지 알아야 하니까! 이때 Link 대신 NavLink를 사용하면 된다.

NavLink는 링크가 활성화되었을때 특정 activeStyle을 사용해 스타일을 입힐 수 있다.

예제코드

  • 이전코드는 아래와 같다
<Link activeStyle={activeStyle} to="/locations/gyonggi">
  경기
</Link>
  • Link 대신 스타일을 입히기 위해서 NavLink를 사용하면 아래와 같다.
import React from 'react';
import { NavLink, Link, Route } from 'react-router-dom';
import Location from './Location';

const Locations = () => {
  const activeStyle = {
    background: 'red',
    color: 'yellow'
  };

  return (
    <div>
      <h1> 도시 목록 </h1>
      <ul>
        <li>
          <NavLink activeStyle={activeStyle} to="/locations/seoul">
            서울
          </NavLink>
        </li>
        <li>
          <NavLink activeStyle={activeStyle} to="/locations/gyonggi">
            경기
          </NavLink>
        </li>
      </ul>
      <Route
        path="/locations"
        exact={true}
        render={() => <div> 지역을 선택해 주세요. </div>}
      />
      <Route path="/locations/:cityname" component={Location} />
    </div>
  );
};

export default Locations;

Router를 이용해 URL로 접속했을때 어떤 컴포넌트로 가는지 정의를 했다.
이제는 URL로 접속했을때 존재하지 않는 URL에 대해서 처리가 필요하고,
단 하나의 라우트만 rendering 하도록 구현이 필요하다.

import React from 'react';
import { Route, Link, Switch } from 'react-router-dom';
import './App.css';

import Home from './components/Home';
import Search from './components/Search';
import Locations from './components/Locations';
import HistorySample from './components/HistorySample';

const App = () => {
  return (
    <div>
      <Link to="/">홈</Link>
      <Link to="/search">검색</Link>
      <Link to="/locations">위치</Link>
      <Link to="/history">히스토리</Link>
      <Switch>
        <Route path="/" component={Home} exact={true}></Route>
        <Route path="/search" component={Search}></Route>
        <Route path="/locations" component={Locations}></Route>
        <Route path="/history" component={HistorySample}></Route>
        <Route
          render={({ location }) => (
            <div>
              <h2> 이 페이지는 존재하지 않는다.</h2>
              <p>{location.pathname}</p>
            </div>
          )}></Route>
      </Switch>
    </div>
  );
};

export default App; 
  • 위 코드에서 path를 명시하지 않으면 해당하는 path가 없을때 해당 Route로 렌더링이 된다.
  • search, locations, history의 파라미터 URL이 아니라면 이 페이지는 존재하지 않는다.의 결과가 나온다.

서브 라우트는 라우트 내부에 라우트를 다시 정의 하는 것을 의미한다. 사용하는 경우에는 App에서 라우팅을 여러군대로 한다면 코드는 App에서 정말 복잡한 결과를 낼것이다. 우리는 여러개의 컴포넌트를 만들고 연관되는 컴포넌트끼리 내부에서 다시 라우터를 정의해 App에서의 다양하고 복잡한 routing을 효과적으로 정리가 가능하다.

예를들어서 Location에 관련된 컴포넌트에서 Location은 Seoul, Gyonggi-do, (...) 가 있을때 App에 모든 도시의 리스트를 정의하기에는 복잡하다. Location Routing Example 에서 App에 seoul, gyonngi-do를 정의 했는데 Locations라는 라우트 컴포넌트를 따로 정의하고, Location 컴포넌트를 서브 라우트로 사용해보자

코드

import React from 'react';
import { Route, Link } from 'react-router-dom';
import './App.css';

import Home from './components/Home';
import Search from './components/Search';
import Locations from './components/Locations';

const App = () => {
  return (
    <div>
      <Link to="/">홈</Link>
      <Link to="/search">검색</Link>
      <Link to="/locations">위치</Link>

      <Route path="/" component={Home} exact={true}></Route>
      <Route path="/search" component={Search}></Route>
      <Route path="/locations" component={Locations}></Route>
    </div>
  );
};

export default App;
import React from 'react';
import { Link, Route } from 'react-router-dom';
import Location from './Location';

const Locations = () => {
  return (
    <div>
      <h1> 도시 목록 </h1>
      <ul>
        <li>
          <Link to="/locations/seoul">서울</Link>
        </li>
        <li>
          <Link to="/locations/gyonggi">경기</Link>
        </li>
      </ul>
      <Route
        path="/locations"
        exact={true}
        render={() => <div> 지역을 선택해 주세요. </div>}
      />
      <Route path="/locations/:cityname" component={Location} />
    </div>
  );
};

export default Locations;

+ Recent posts