Skip to content

Commit

Permalink
Add in lessons
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanflorence committed Feb 10, 2016
1 parent f9f476f commit 50f7f54
Show file tree
Hide file tree
Showing 17 changed files with 1,251 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bundle.js
*.bundle.js
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
React Router Tutorial
=====================

Quick lessons for getting up-to-speed with React Router.

See [01-setting-up.md](/lessons/01-setting-up.md) to get started.

Each lesson has a commit for the final code so you can `git checkout
<previous lesson final sha>` before starting a new one if you'd like.

Missing stuff that will come eventually, hopefully ... maybe.

1. an app that isn't completely pointless
- egghead.io videos
- code splitting
- location state
- data integration

33 changes: 33 additions & 0 deletions lessons/01-setting-up.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Setting up the Project

First you'll need [Node.js](https://nodejs.org) and the package manager
that comes with it: [npm](https://www.npmjs.com/).

Once you've got that working, head to the command line where we'll set
up our project.

## Clone the Tutorial

```
git clone <tutorial url>
cd react-router-tutorial
git checkout start
npm start
```

Now open up http://localhost:8080

Feel free to poke around the code to see how we're using webpack and npm
scripts to run the app.

You should see a "Hello React Router" message in the browser.

## Make Some Changes

Open up `modules/App.js` and change the text to something like "Hello
<your name>". The browser automatically reloads with your new code.

---

[Next: Rendering a Router](02-rendering-a-router.md)

88 changes: 88 additions & 0 deletions lessons/02-rendering-a-router.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Rendering a Router

At its heart, React Router is a component.

```js
render(<Router/>, document.getElementById('app'))
```

That's not going display anything until we configure a route.

Open up `index.js` and

1. import `Router` and `Route`
2. render a `Router` instead of `App`

```js
// ...
import { Router, Route, hashHistory } from 'react-router'

render((
<Router history={hashHistory}>
<Route path="/" component={App}/>
</Router>
), document.getElementById('app'))
```

Make sure your server is running with `npm start` and then visit
http://localhost:8080

You should get the same screen as before, but this time with some junk
in the URL. We're using `hashHistory`--it manages the routing history
with the hash portion of the url. It's got that extra junk to shim some
behavior the browser has natively when using real urls. We'll change
this to use real urls later and lose the junk, but for now, this works
great because it doesn't require any server-side configuration.

## Adding More Screens

Create two new components at:

- `modules/About.js`
- `modules/Repos.js`

```js
// modules/About.js
import React from 'react'

export default React.createClass({
render() {
return <div>About</div>
}
})
```

```js
// modules/Repos.js
import React from 'react'

export default React.createClass({
render() {
return <div>Repos</div>
}
})
```

Now we can couple them to the app at their respective paths.

```js
import About from './modules/About'
import Repos from './modules/Repos'

render((
<Router history={hashHistory}>
<Route path="/" component={App}/>
{/* add the routes here */}
<Route path="/repos" component={Repos}/>
<Route path="/about" component={About}/>
</Router>
), document.getElementById('app'))
```

Now visit http://localhost:8080/#/about and
http://localhost:8080/#/repos

---

[Next: Navigating With Link](03-navigating-with-link.md)

34 changes: 34 additions & 0 deletions lessons/03-navigating-with-link.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Navigating with Link

Perhaps the most used component in your app is `Link`. Its almost
identical to the `<a/>` tag you're used to except that its aware of
the `Router` it was rendered in.

Lets create some navigation in our `App` component.

```js
// modules/App.js
import { Link } from 'react-router'

export default React.createClass({
render() {
return (
<div>
<h1>React Router Tutorial</h1>
<ul role="nav">
<li><Link to="/about">About</Link></li>
<li><Link to="/repos">Repos</Link></li>
</ul>
</div>
)
}
})
```

Now visit http://localhost:8080/ and click the links, click back, click
forward. It works!

---

[Next: Nested Routes](04-nested-routes.md)

126 changes: 126 additions & 0 deletions lessons/04-nested-routes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Nested Routes

The navigation we added to `App` should probably be present on every
screen. Without React Router, we could wrap that `ul` into a
component, say `Nav`, and render a `Nav` on every one of our screens.

This approach isn't as clean as the application grows. React Router
provides another way to share UI like this with nested routes, a trick
it learned from [Ember](http://emberjs.com) (/me tips hat).

## Nested UI and Nested URLs

Have you ever noticed your app is just a series of boxes inside boxes
inside boxes? Have you also noticed your URLs tend to be coupled to that
nesting? For example given this url, `/repos/123`, our
components would probably look like this:

```js
<App> {/* / */}
<Repos> {/* /repos */}
<Repo/> {/* /repos/123 */}
</Repos>
</App>
```

And our UI something like:

```
+-------------------------------------+
| Home Repos About | <- App
+------+------------------------------+
| | |
Repos -> | repo | Repo 1 |
| | |
| repo | Boxes inside boxes |
| | inside boxes ... | <- Repo
| repo | |
| | |
| repo | |
| | |
+------+------------------------------+
```

React Router embraces this by letting you nest your routes, which
automatically becomes nested UI.

## Sharing Our Navigation

Lets nest our `About` and `Repos` components inside of `App` so that we
can share the navigation with all screens in the app. We do it in two
steps:

First, let the `App` `Route` have children, and move the other routes
underneath it.

```js
// index.js
// ...
render((
<Router history={hashHistory}>
<Route path="/" component={App}>
{/* make them children of `App` */}
<Route path="/repos" component={Repos}/>
<Route path="/about" component={About}/>
</Route>
</Router>
), document.getElementById('app'))
```

Next, render children inside of `App`.

```js
// modules/App.js
// ...
render() {
return (
<div>
<h1>Ghettohub Issues</h1>
<ul role="nav">
<li><Link to="/about">About</Link></li>
<li><Link to="/repos">Repos</Link></li>
</ul>

{/* add this */}
{this.props.children}

</div>
)
}
// ...
```

Alright, now go click the links and notice that the `App` component
continues to render while the child route's component gets swapped
around as `this.props.children` :)

React Router is constructing your UI like this:

```js
// at /about
<App>
<About/>
</App>

// at /repos
<App>
<Repos/>
</App>
```

## By Small and Simple Things are Great Things Brought to Pass

The best way to build large things is to stitch small things together.

This is the real power of React Router, every route can be developed
(even rendered!) as an independent application. Your route configuration
stitches all these apps together however you'd like. Applications
inside of Applications, boxes inside of boxes.

What happens if you move the `About` route outside of `App`?

Okay, now put it back.

---

[Next: Active Links](05-active-links.md)
85 changes: 85 additions & 0 deletions lessons/05-active-links.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Active Links

One way that `Link` is different from `a` is that it knows if the path
it links to is active so you can style it differently.

## Active Styles

Let's see how it looks with inline styles, add `activeStyle` to your
`Links`s.

```js
// modules/App.js
<li><Link to="/about" activeStyle={{ color: 'red' }}>About</Link></li>
<li><Link to="/repos" activeStyle={{ color: 'red' }}>Repos</Link></li>
```

How as you navigate, the active link is red.

## Active Class Name

You can also use an active class name instead of inline-styles.

```js
<li><Link to="/about" activeClassName="active">About</Link></li>
<li><Link to="/repos" activeClassName="active">Repos</Link></li>
```

We don't have a stylesheet on the page yet though. Lets add one--extra
points if you can add a `link` tag from memory. Double extra points if
you can leave the attributes unquoted, against your better judgement.

```html
<link rel=stylesheet href=index.css />
```

And the css file:

```css
.active {
color: green;
}
```

You'll need to manually refresh the browser since Webpack isn't building
our `index.html`.

## Nav Link Wrappers

Most links in your site don't need to know they are active, usually just
primary navigation links need to know. Its useful to wrap those so you
don't have to remember what your `activeClassName` or `activeStyle` is
everywhere.

Create a new file at `modules/NavLink.js` that looks like this:

```js
// modules/NavLink.js
import React from 'react'
import { Link } from 'react-router'

export default React.createClass({
render() {
return <Link {...this.props} activeClassName="active"/>
}
})
```

Now you can go change your links to `NavLink`s.

```js
// App.js
import NavLink from './NavLink'

// ...

<li><NavLink to="/about">About</NavLink></li>
<li><NavLink to="/repos">Repos</NavLink></li>
```

Oh, how beautiful upon the renders is the composability of components.

---

[Next: Params](06-params.md)

Loading

0 comments on commit 50f7f54

Please sign in to comment.