React-router 14 个 demo

01、Setting up the Project

First you'll need Node.js and the package manager
that comes with it: npm.

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

Clone the Tutorial

git clone https://github.com/reactjs/react-router-tutorial
cd react-router-tutorial
cd lessons/01-setting-up
npm install
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.


02、 Rendering a Route

At its heart, React Router is a component.

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

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

Open up index.js and

  1. import Router, Route, and hashHistory
  2. render a Router instead of App
// ...
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
// modules/About.js
import React from 'react'

export default React.createClass({
  render() {
    return <div>About</div>
  }
})
// 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.

// insert into index.js
import About from './modules/About'
import Repos from './modules/Repos'

render((
  <Router >
    <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


03、 Navigating with Link

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

Let's create some navigation in our App component.

// modules/App.js
import React from 'react'
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!


04、 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 (/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:

<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

Let's 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.

// 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.

// modules/App.js
// ...
  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>

        {/* 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:

// 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.


05、 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.

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

Now as you navigate, the active link is red.

Active Class Name

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

// modules/App.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
point if you can add a link tag from memory.

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

And the CSS file:

.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. It's useful to wrap those so you
don't have to remember what your activeClassName or activeStyle is
everywhere.

We will use a spread operator here, the three dots. It clones our props
and in this use case it clones activeClassName to our desired component for
us to benefit from.

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

// 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 NavLinks.

// modules/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.


06、 URL Params

Consider the following URLs:

/repos/reactjs/react-router
/repos/facebook/react

These URLs would match a route path like this:

/repos/:userName/:repoName

The parts that start with : are URL parameters whose values will be
parsed out and made available to route components on
this.props.params[name].

Adding a Route with Parameters

Let's teach our app how to render screens at /repos/:userName/:repoName.

First we need a component to render at the route, make a new file at
modules/Repo.js that looks something like this:

// modules/Repo.js
import React from 'react'

export default React.createClass({
  render() {
    return (
      <div>
        <h2>{this.props.params.repoName}</h2>
      </div>
    )
  }
})

Now open up index.js and add the new route.

// ...
// import Repo
import Repo from './modules/Repo'

render((
  <Router history={hashHistory}>
    <Route path="/" component={App}>
      <Route path="/repos" component={Repos}/>
      {/* add the new route */}
      <Route path="/repos/:userName/:repoName" component={Repo}/>
      <Route path="/about" component={About}/>
    </Route>
  </Router>
), document.getElementById('app'))

Now we can add some links to this new route in Repos.js.

// Repos.js
import { Link } from 'react-router'
// ...
export default React.createClass({
  render() {
    return (
      <div>
        <h2>Repos</h2>

        {/* add some links */}
        <ul>
          <li><Link to="/repos/reactjs/react-router">React Router</Link></li>
          <li><Link to="/repos/facebook/react">React</Link></li>
        </ul>

      </div>
    )
  }
})

Now go test your links out. Note that the parameter name in the route
path becomes the property name in the component. Both repoName and
userName are available on this.props.params of your component. You
should probably add some prop types to help others and yourself out
later.


07、 More Nesting

Notice how the list of links to different repositories goes away when we
navigate to a repository? What if we want the list to persist, just like
the global navigation persists?

Try to figure that out before reading on.

...

First, nest the Repo route under the Repos route. Then go render
this.props.children in Repos.

// index.js
// ...
<Route path="/repos" component={Repos}>
  <Route path="/repos/:userName/:repoName" component={Repo}/>
</Route>
// Repos.js
// ...
<div>
  <h2>Repos</h2>
  <ul>
    <li><Link to="/repos/reactjs/react-router">React Router</Link></li>
    <li><Link to="/repos/facebook/react">React</Link></li>
  </ul>
  {/* will render `Repo.js` when at /repos/:userName/:repoName */}
  {this.props.children}
</div>

Active Links

Let's bring in our NavLink from before so we can add the active
class name to these links:

// modules/Repos.js
// import it
import NavLink from './NavLink'

// ...
<li><NavLink to="/repos/reactjs/react-router">React Router</NavLink></li>
<li><NavLink to="/repos/facebook/react">React</NavLink></li>
// ...

Notice how both the /repos link up top and the individual repo links are
both active? When child routes are active, so are the parents.


08、 Index Routes

When we visit / in this app it's just our navigation and a blank page.
We'd like to render a Home component there. Lets create a Home
component and then talk about how to render it at /.

// modules/Home.js
import React from 'react'

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

One option is to see if we have any children in App, and if not,
render Home:

// modules/App.js
import Home from './Home'

// ...
<div>
  {/* ... */}
  {this.props.children || <Home/>}
</div>
//...

This would work fine, but its likely we'll want Home to be attached to
a route like About and Repos in the future. A few reasons include:

  1. Participating in a data fetching abstraction that relies on matched
    routes and their components.
  2. Participating in onEnter hooks
  3. Participating in code-splitting

Also, it just feels good to keep App decoupled from Home and let the
route config decide what to render as the children. Remember, we want to
build small apps inside small apps, not big ones!

Let's add a new route to index.js.

// index.js
// new imports:
// add `IndexRoute` to 'react-router' imports
import { Router, Route, hashHistory, IndexRoute } from 'react-router'
// and the Home component
import Home from './modules/Home'

// ...

render((
  <Router history={hashHistory}>
    <Route path="/" component={App}>

      {/* add it here, as a child of `/` */}
      <IndexRoute component={Home}/>

      <Route path="/repos" component={Repos}>
        <Route path="/repos/:userName/:repoName" component={Repo}/>
      </Route>
      <Route path="/about" component={About}/>
    </Route>
  </Router>
), document.getElementById('app'))

Now open http://localhost:8080 and you'll see the new component is
rendered.

Notice how the IndexRoute has no path. It 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.

Index routes can twist people's brains up sometimes. Hopefully it will
sink in with a bit more time. Just think about a web server that looks
for index.html when you're at /. Same idea, React Router looks for
an index route if a route's path matches exactly.


09、 Index Links

Have you noticed in our app that we don't have any navigation to get
back to rendering the Home component?

Lets add a link to / and see what happens:

// in App.js
// ...
<li><NavLink to="/">Home</NavLink></li>
// ...

Now navigate around. Notice anything weird? The link to Home is always
active! As we learned earlier, parent routes are active when child routes
are active. Unfortunately, / is the parent of everything.

For this link, we want it to only be active when the index route is
active. There are two ways to let the router know you're linking to the
"index route" so it only adds the active class (or styles) when the
index route is rendered.

IndexLink

First let's use the IndexLink instead of NavLink

// App.js
import { IndexLink } from 'react-router'

// ...
<li><IndexLink to="/" activeClassName="active">Home</IndexLink></li>

Fixed! Now this link is only "active" when we're at the index route. Go
ahead and click around to see.

onlyActiveOnIndex Property

We can use Link as well by passing it the onlyActiveOnIndex prop
(IndexLink just wraps Link with this property for convenience).

<li><Link to="/" activeClassName="active" onlyActiveOnIndex={true}>Home</Link></li>

That's fine, but we already abstracted away having to know what the
activeClassName is with Nav.

Remember, in NavLink we're passing along all of our props to Link with
the {...spread} syntax, so we can actually add the prop when we render
a NavLink and it will make its way down to the Link:

<li><NavLink to="/" onlyActiveOnIndex={true}>Home</NavLink></li>

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • rljs by sennchi Timeline of History Part One The Cognitiv...
    sennchi阅读 12,168评论 0 10
  • 对话结束
    田大明阅读 1,787评论 0 0
  • 最近这几年“大数据”无疑是风口浪尖上的新话题、新事物,你一个卖货、搞营销的如果不说点大数据的词都不好意思跟人开口,...
    zhulu2017阅读 8,396评论 0 1
  • 脚步匆忙 却无法挽留逝去的时光 青春激昂 把保家卫国的责任扛在肩上 跪别爹娘 来到挥洒豪迈的地方 告别儿时的鲁莽 ...
    吴枫WF阅读 1,450评论 0 0

友情链接更多精彩内容