[React] react-router on redgoose note

[React] react-router

Nest: Development Category: Javascript 2015-12-04

react-router를 사용할일이 생겨서 삽질을 하게 되었다.
react router 기능을 가진 모듈중에 가장 인기있는게 react-router 이다.

그런데 require를 사용할 수 없는 환경이어서 브라우저로 소스를 가져와야 했다.
node.js 형식의 스크립트를 빌드하기 위하여 browserfly를 많이 쓰는데 테스트해보니 라우터에 관한 라이브러리까지 몽땅 합쳐버리다보니 빌드할때 4,5초나 걸리는거였다.
그래서 라이브러리를 require를 사용하지 않고, <script src=""> 형식으로 불러오고 쓸 수 있는 방법에 대해서 찾아보게 되었다. 아무래도 require는 인연이 없는듯.. ㅠㅠ

react-router

https://www.npmjs.com/package/react-router

npm의 react-router 모듈 페이지에 가면 중간에 UMD 섹션이 있다.
여기서 CDN 안내에서 소스를 받을 수 있는 링크가 있는데 그 링크로 사용하거나 소스를 다운받아서 사용할 수 있다.

<script src="https://cdnjs.cloudflare.com/ajax/libs/react-router/1.0.0/ReactRouter.min.js"></script>

소스에서 보면 이렇게 사용하면 되는것이라고 나와있다. 이것으로 Router 컴포넌트를 곧장 사용할 수 있게 되었다.

// using an es6 transpiler, like babel 
import { Router, Route, Link } from 'react-router/umd/ReactRouter'

// using globals 
var Router = window.ReactRouter.Router;
var Link = window.ReactRouter.Link;
var Route = window.ReactRouter.Route;

gulpfile.js

jsx로 코딩한다면 babel로 빌드는 항상 해야할 것이다. 대략적으로 다음과 같이 태스크를 만들었다.

var gulp = require('gulp');
var uglify = require('gulp-uglify');
var babel = require('gulp-babel');
var concat = require('gulp-concat');

// compile react
gulp.task('react', function(){
    return gulp.src([ 'src/**/!(index)*.jsx', 'src/**/index.jsx'])
        .pipe(babel({
            plugins : ['transform-react-jsx'],
            presets : ['es2015']
        }))
        .pipe(uglify())
        .pipe(concat('app.js', { newLine: '\n' }))
        .pipe(gulp.dest("dist"));
});

gulp.task('react:watch', function(){
    gulp.watch('src/**/*.jsx', ['react']);
});

concat으로 소스를 합칠때 index.jsx파일은 실행하는 코드가 들어있어 가장 마지막에 들어가야할 필요가 있어서 gulp.src([ 'src/**/!(index)*.jsx', 'src/**/index.jsx'])형식으로 수정했다.
es2015 형식에 흥미가 생겨 es2015 형식으로 코딩하면서 babel 프리셋으로 es2015를 넣었다. 그 전에 npm install --save-dev babel-preset-es2015 명령으로 모듈을 설치해줘야 한다.

History

데모를 를 만들어보니 ?_k=abc123 값이 계속 붙어대는것이다.
찾아보니 대략적으로 history에 관한 부분때문에 달리는거 같은데 없애는 방법이 있었지만 require를 사용하지 못하는 환경에서는 역시 애를 먹는다. 대부분의 해결방법에서는 createBrowserHistory 모듈을 사용해라고 해서 찾아보게 되었다.

import createBrowserHistory from 'history/lib/createBrowserHistory';
...

<Router history={createBrowserHistory()}>

이것은 require를 쓰는 방법이라서 사용할 수 없는 방식이다.

https://www.npmjs.com/package/history
일단 History 모듈 사이트에서 인스톨 섹션에서 umd 형식의 소스를 cdn 주소가 있는걸 보게 되었다.

<script src="https://npmcdn.com/history/umd/History.min.js"></script>

Load library

js에서 require로 모듈을 불러오지 않기 때문에 html에서 <script src=""/>로 모듈을 불러와야한다.

<div id="app"></div>

<script src="react-0.14.3.js"></script>
<script src="react-dom-0.14.3.min.js"></script>
<script src="ReactRouter.min.js"></script>
<script src="History.min.js"></script>

<!-- build js file -->
<script src="dist/app.js"></script>

src/index.jsx

재료는 준비되었으니 빌드할 소스를 코딩한다.

const Router = window.ReactRouter.Router;
const Link = window.ReactRouter.Link;
const Route = window.ReactRouter.Route;
const IndexRoute = window.ReactRouter.IndexRoute;
const createHashHistory = window.History.createHashHistory;

// render router
ReactDOM.render(
    (
        <Router history={createHashHistory({ queryKey: false })}>
            <Route path="/" component={App}>
                <Route path="user" component={User}/>
            </Route>
        </Router>
    ),
    document.getElementById('app')
);

라우터에 모듈을 컴포넌트 상수로 할당한 부분

const Router = window.ReactRouter.Router;
const Link = window.ReactRouter.Link;
const Route = window.ReactRouter.Route;
const IndexRoute = window.ReactRouter.IndexRoute;

History 모듈을 컴포넌트 상수로 할당한 부분

const createHashHistory = window.History.createHashHistory;

History 모듈을 console로 뒤져보니 createBrowserHistory메서드가 없었다.
그래서 다른 메서드들을 하나씩 테스트해보면서 삽질을 해보니 createHashHistory 메서드로 사용할 수 있었다. react-router는 #해쉬 문자로 url 처리를 하기때문인듯..

Render

라우터 컴포넌트 렌더를 하기위한 코드

ReactDOM.render(
    (
        <Router history={createHashHistory({ queryKey: false })}>
            <Route path="/" component={App}>
                <Route path="user" component={User}/>
            </Route>
        </Router>
    ),
    document.getElementById('app')
);

<Router history={createHashHistory({ queryKey: false })}> 부분에 _k 파라메터를 없애기 위하여 프로퍼티를 넣었다.

url주소는 다음과 같이 이동하도록 처리했다.

URL Component
/ <App/>
/user <User/>

App.jsx

/로 이동할때 불러오는 컴포넌트

const App = React.createClass({
    render() {
        return (
            <div>
                <h1>Hello App</h1>
                {this.props.children}
            </div>
        )
    }
});

주의깊게 봐야할 부분은 {this.props.children}
this.props.children 값은 하위 Route를 가르킨다. 여러개가 있다면 다르게 표시될텐데 console로 this.props값을 체크해가면서 넣으면 될것이다.

User.jsx

App 컴포넌트의 자식으로 출력되는 컴포넌트

const User = React.createClass({
    render() {
        return (
            <div>
                <h1>Hello User</h1>
            </div>
        )
    }
});

ps.
전체적인 소스는 여유가 생긴다면 정리해보겠음. ㅠㅠ