Skip to content

Commit c0d5d6c

Browse files
committed
learn react-router
1 parent 66d013c commit c0d5d6c

File tree

14 files changed

+278
-8
lines changed

14 files changed

+278
-8
lines changed

lessons/01-setting-up/index.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
import React from 'react'
22
import { render } from 'react-dom'
3-
import App from './modules/App'
4-
render(<App/>, document.getElementById('app'))
3+
import {Router, hashHistory, browserHistory} from 'react-router'
4+
import routes from './modules/routes'
5+
6+
// render(<App/>, document.getElementById('app'))
7+
render((
8+
<Router routes={routes} history={browserHistory}>
9+
{/*<Router history={hashHistory}>*/}
10+
</Router>
11+
), document.getElementById('app'));
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import React from 'react'
2+
3+
export default React.createClass({
4+
render() {
5+
return <div>About</div>
6+
}
7+
})

lessons/01-setting-up/modules/App.js

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,42 @@
11
import React from 'react'
2+
import {Link, IndexLink} from 'react-router'
3+
import NavLink from './NavLink'
4+
import Home from './Home'
25

36
export default React.createClass({
47
render() {
5-
return <div>Hello, React Router!</div>
8+
return (
9+
<div>
10+
<h1>Hello, React Router!</h1>
11+
<ul role="nav">
12+
<li>
13+
<NavLink to="/" onlyActiveOnIndex={true}>Home</NavLink>
14+
</li>
15+
<li>
16+
<NavLink to="/about">About</NavLink>
17+
</li>
18+
<li>
19+
<NavLink to="/repos">Repos</NavLink>
20+
</li>
21+
</ul>
22+
23+
{/*if we have any children in App, and if not, render Home*/}
24+
25+
{this.props.children || <Home/>}
26+
</div>
27+
)
628
}
729
})
30+
31+
32+
/* React Router is constructing your UI like this:
33+
// at /about
34+
<App>
35+
<About/>
36+
</App>
37+
38+
// at /repos
39+
<App>
40+
<Repos/>
41+
</App>
42+
*/

lessons/01-setting-up/modules/Home.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* Created by sammy on 17/3/9.
3+
*/
4+
import React from 'react'
5+
6+
export default React.createClass({
7+
render() {
8+
return <div>Home</div>
9+
}
10+
})
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* Created by sammy on 17/3/9.
3+
*/
4+
import React from 'react'
5+
import { Link } from 'react-router'
6+
7+
export default React.createClass({
8+
render() {
9+
return <Link {...this.props} activeClassName="active"/>
10+
}
11+
})

lessons/01-setting-up/modules/Repo.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* Created by sammy on 17/3/9.
3+
*/
4+
import React from 'react'
5+
6+
export default React.createClass({
7+
render() {
8+
return (
9+
<div>
10+
<h2>{this.props.params.repoName}</h2>
11+
</div>
12+
)
13+
}
14+
})
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import React from 'react'
2+
import {browserHistory} from 'react-router'
3+
import NavLink from './NavLink'
4+
5+
export default React.createClass({
6+
7+
contextTypes: {
8+
router: React.PropTypes.object
9+
},
10+
11+
handleSubmit(event) {
12+
event.preventDefault();
13+
const userName = event.target.elements[0].value;
14+
const repo = event.target.elements[1].value;
15+
const path = `/repos/${userName}/${repo}`;
16+
console.log(path);
17+
this.context.router.push(path);
18+
// browserHistory.push(path);
19+
},
20+
21+
render() {
22+
return (
23+
<div>
24+
<h2>Repos</h2>
25+
26+
{/* add some links */}
27+
<ul>
28+
<li><NavLink to="/repos/reactjs/react-router">React Router</NavLink></li>
29+
<li><NavLink to="/repos/facebook/react">React</NavLink></li>
30+
<li>
31+
<from onSubmit={this.handleSubmit}>
32+
<input type="text" placeholder="userName"/> / {' '}
33+
<input type="text" placeholder="repo"/>{' '}
34+
<button type="submit">Go</button>
35+
</from>
36+
</li>
37+
</ul>
38+
39+
{/* will render `Repo.js` when at /repos/:userName/:repoName */}
40+
{this.props.children}
41+
</div>
42+
)
43+
}
44+
})
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* Created by sammy on 17/3/10.
3+
*/
4+
import React from 'react'
5+
import { Route, IndexRoute } from 'react-router'
6+
import App from './App'
7+
import About from './About'
8+
import Repos from './Repos'
9+
import Repo from './Repo'
10+
import Home from './Home'
11+
12+
module.exports = (
13+
<Route path="/" component={App}>
14+
<IndexRoute component={Home}/>
15+
<Route path="/repos" component={Repos}>
16+
<Route path="/repos/:userName/:repoName" component={Repo}/>
17+
</Route>
18+
<Route path="/about" component={About}/>
19+
</Route>
20+
)

lessons/01-setting-up/package.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,19 @@
44
"description": "",
55
"main": "index.js",
66
"scripts": {
7-
"start": "webpack-dev-server --inline --content-base ."
7+
"start": "if-env NODE_ENV=production && npm run start:prod || npm run start:dev",
8+
"start:dev": "webpack-dev-server --inline --content-base public/ --history-api-fallback",
9+
"start:prod": "npm run build && node server.bundle.js",
10+
"build:client": "webpack",
11+
"build:server": "webpack --config webpack.server.config.js",
12+
"build": "npm run build:client && npm run build:server"
813
},
914
"author": "",
1015
"license": "ISC",
1116
"dependencies": {
17+
"compression": "^1.6.2",
18+
"express": "^4.15.2",
19+
"if-env": "^1.0.0",
1220
"react": "^0.14.7",
1321
"react-dom": "^0.14.7",
1422
"react-router": "^2.0.0"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.active {
2+
color: green;
3+
}

lessons/01-setting-up/index.html renamed to lessons/01-setting-up/public/index.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
<html>
33
<meta charset=utf-8/>
44
<title>My First React Router App</title>
5+
<link rel="stylesheet" href="/index.css">
56
<div id=app></div>
6-
<script src="bundle.js"></script>
7+
<script src="/bundle.js"></script>

lessons/01-setting-up/server.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* Created by sammy on 17/3/9.
3+
*/
4+
5+
import React from 'react'
6+
import { renderToString } from 'react-dom/server' // we'll use this to render our app to an html string
7+
import { match, RouterContext } from 'react-router' // and these to match the url to routes and then render
8+
import routes from './modules/routes'
9+
10+
var express = require('express');
11+
var path = require('path');
12+
var compression = require('compression');
13+
14+
var app = express();
15+
16+
app.use(compression()); // The middleware will attempt to compress response bodies for all request
17+
18+
app.use(express.static(path.join(__dirname, 'public')));
19+
20+
// send all requests to index.html so browserHistory works
21+
app.get("*", (req, res) => {
22+
// match the routes to the url
23+
match({routes: routes, location: req.url}, (err, redirect, props) => {
24+
25+
if (err) {
26+
// there was an error somewhere during route matching
27+
res.status(500).send(err.message);
28+
} else if (redirect) {
29+
// we haven't talked about `onEnter` hooks on routes, but before a
30+
// route is entered, it can redirect. Here we handle on the server.
31+
res.redirect(redirect.pathname + redirect.search)
32+
} else if (props) {
33+
// if we got props then we matched a route and can render
34+
35+
// `RouterContext` is what the `Router` renders. `Router` keeps these
36+
// `props` in its state as it listens to `browserHistory`. But on the
37+
// server our app is stateless, so we need to use `match` to
38+
// get these props before rendering.
39+
const appHtml = renderToString(<RouterContext {...props}/>);
40+
41+
// dump the HTML into a template, lots of ways to do this, but none are
42+
// really influenced by React Router, so we're just using a little
43+
// function, `renderPage`
44+
res.send(renderPage(appHtml))
45+
} else {
46+
// no errors, no redirect, we just didn't match anything
47+
res.status(404).send("Not Found");
48+
}
49+
50+
51+
});
52+
// res.sendFile(path.join(__dirname, 'public','index.html'))
53+
});
54+
55+
function renderPage(appHtml) {
56+
return `
57+
<!doctype html public="storage">
58+
<html>
59+
<meta charset=utf-8/>
60+
<title>My First React Router App</title>
61+
<link rel=stylesheet href=/index.css>
62+
<div id=app>${appHtml}</div>
63+
<script src="/bundle.js"></script>
64+
`
65+
}
66+
67+
var PORT = process.env.PORT || 8080;
68+
app.listen(POST, function(){
69+
console.log("Production Express server running at localhost:"+PORT);
70+
});
Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
1+
var webpack = require('webpack');
2+
13
module.exports = {
24
entry: './index.js',
35

46
output: {
7+
path: 'public',
58
filename: 'bundle.js',
6-
publicPath: ''
9+
publicPath: '/'
710
},
811

912
module: {
1013
loaders: [
1114
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader?presets[]=es2015&presets[]=react' }
1215
]
13-
}
14-
}
16+
},
17+
18+
plugins: process.env.NODE_ENV === 'production' ? [
19+
new webpack.optimize.DedupePlugin(),
20+
new webpack.optimize.OccurrenceOrderPlugin(),
21+
new webpack.optimize.UglifyJsPlugin()
22+
] : [],
23+
};
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
var fs = require('fs');
2+
var path = require('path');
3+
4+
module.exports = {
5+
entry: path.resolve(__dirname, 'server.js'),
6+
7+
output: {
8+
filename: 'server.bundle.js'
9+
},
10+
11+
target: 'node',
12+
13+
// keep node_module paths out of the bundle
14+
externals: fs.readdirSync(path.resolve(__dirname, 'node_modules')).concat([
15+
'react-dom/server', 'react/addons',
16+
]).reduce(function(ext, mod) {
17+
ext[mod] = 'common.js' + mod;
18+
return ext;
19+
}, {}),
20+
21+
node: {
22+
__filename: true,
23+
__dirname: true
24+
},
25+
26+
module: {
27+
loaders: [
28+
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader?presets[]=es2015&presets[]=react' }
29+
]
30+
}
31+
}

0 commit comments

Comments
 (0)