Skip to content

Commit 5e94bb1

Browse files
committed
Completed tutorial
1 parent 718ffec commit 5e94bb1

File tree

15 files changed

+308
-13
lines changed

15 files changed

+308
-13
lines changed

lessons/01-setting-up/index.html

Lines changed: 0 additions & 6 deletions
This file was deleted.

lessons/01-setting-up/index.js

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,40 @@
1+
// import React from 'react'
2+
// import { render } from 'react-dom'
3+
// import App from './modules/App'
4+
5+
// // import { Router, Route, hashHistory, IndexRoute } from 'react-router'
6+
// import { Router, Route, browserHistory, IndexRoute } from 'react-router'
7+
// import About from './modules/About'
8+
// import Repos from './modules/Repos'
9+
// import Repo from './modules/Repo'
10+
// import Home from './modules/Home'
11+
12+
13+
// // IndexRoute becomes this.props.children of the parent when no other child of the parent matches, or in other words, when the parent's route matches exactly
14+
15+
// render((
16+
// <Router history={browserHistory}>
17+
// <Route path="/" component={App}>
18+
// <IndexRoute component={Home} />
19+
// <Route path="/about" component={About} />
20+
// <Route path="/repos" component={Repos}>
21+
// <Route path="/repos/:userName/:repoName" component={Repo} />
22+
// </Route>
23+
// </Route>
24+
// </Router>
25+
// ), document.getElementById('app'))
26+
27+
28+
// ^before server
29+
// after server:
30+
131
import React from 'react'
232
import { render } from 'react-dom'
3-
import App from './modules/App'
4-
render(<App/>, document.getElementById('app'))
33+
import { Router, browserHistory } from 'react-router'
34+
// import routes and pass them into <Router/>
35+
import routes from './modules/routes'
36+
37+
render(
38+
<Router routes={routes} history={browserHistory}/>,
39+
document.getElementById('app')
40+
)
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 & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,40 @@
11
import React from 'react'
2+
import NavLink from './NavLink'
3+
import Home from './Home'
4+
import { IndexLink } from 'react-router'
25

36
export default React.createClass({
4-
render() {
5-
return <div>Hello, React Router!</div>
6-
}
7+
render() {
8+
// return (
9+
// <div>{this.props.children || <Home/>}</div>
10+
// )
11+
return (
12+
<div style={{ backgroundColor: 'lightgrey' }}>
13+
<h1>React Router Tutorial</h1>
14+
<ul role="nav">
15+
<li>
16+
<NavLink to="/" onlyActiveOnIndex={true}>Home</NavLink>
17+
</li>
18+
<li>
19+
<NavLink to="/about">About</NavLink>
20+
</li>
21+
<li>
22+
<NavLink to="/repos">Repos</NavLink>
23+
</li>
24+
</ul>
25+
{this.props.children}
26+
</div>
27+
)
28+
}
729
})
30+
31+
32+
/*
33+
34+
<IndexLink to="/" activeClassName="active">Home</IndexLink>
35+
can also be
36+
<Link to="/" activeClassName="active" onlyActiveOnIndex={true}>Home</Link>
37+
but we're using spread (like this: <Link {...this.props} > ...etc)
38+
so we can do it the above way
39+
40+
*/

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import React from 'react';
2+
3+
class Home extends React.Component {
4+
constructor(props) {
5+
super(props);
6+
this.displayName = 'Home';
7+
}
8+
render() {
9+
return <div>Home</div>;
10+
}
11+
}
12+
13+
export default Home;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import React from 'react'
2+
import { Link } from 'react-router'
3+
4+
export default React.createClass({
5+
render() {
6+
return <Link {...this.props} activeClassName="active" />
7+
}
8+
})

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

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

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.13.4",
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+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!doctype html public "storage">
2+
<html>
3+
<meta charset=utf-8/>
4+
<title>My First React Router App</title>
5+
<link rel="stylesheet" href="/index.css" /> <!-- (for browserHistory) -->
6+
<!-- <link rel="stylesheet" href="index.css" /> (for hashHistory)-->
7+
<div id=app></div>
8+
<script src="/bundle.js"></script> <!-- (for browserHistory) -->
9+
<!-- <script src="bundle.js"></script> (for hashHistory) -->

lessons/01-setting-up/server.js

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

46
output: {
7+
path: 'public',
58
filename: 'bundle.js',
69
publicPath: ''
710
},
@@ -10,5 +13,11 @@ module.exports = {
1013
loaders: [
1114
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader?presets[]=es2015&presets[]=react' }
1215
]
13-
}
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+
] : [],
1423
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
var fs = require('fs')
2+
var path = require('path')
3+
4+
module.exports = {
5+
6+
entry: path.resolve(__dirname, 'server.js'),
7+
8+
output: {
9+
filename: 'server.bundle.js'
10+
},
11+
12+
target: 'node',
13+
14+
// keep node_module paths out of the bundle
15+
externals: fs.readdirSync(path.resolve(__dirname, 'node_modules')).concat([
16+
'react-dom/server', 'react/addons',
17+
]).reduce(function (ext, mod) {
18+
ext[mod] = 'commonjs ' + mod
19+
return ext
20+
}, {}),
21+
22+
node: {
23+
__filename: true,
24+
__dirname: true
25+
},
26+
27+
module: {
28+
loaders: [
29+
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader?presets[]=es2015&presets[]=react' }
30+
]
31+
}
32+
33+
}

0 commit comments

Comments
 (0)