晴明的博客园 GitHub      CodePen      CodeWars     

[react] react-router、 react-router-redux

import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, hashHistory, IndexRoute } from 'react-router';
import App from './components/App';
import Home from './components/Home';
import Repos from './components/Repos';
import About from './components/About';
import User from './components/User';
import Contacts from './components/Contacts';

ReactDOM.render(
  <Router history={hashHistory}>
    <Route path="/" component={App}>
      <IndexRoute component={Home} />
      <Route path="/repos/:name" component={Repos} />
      <Route path="/about" component={About} />
      <Route path="/user" component={User} />
      <Route path="/contacts" component={Contacts} />
    </Route>
  </Router>,
  document.getElementById('app'));

  /* 另外一种写法
    const routes = (
        <Route path="/" component={App}>
          <IndexRoute component={Home} />
          <Route path="/repos/:name" component={Repos} />
          <Route path="/about" component={About} />
          <Route path="/user" component={User} />
          <Route path="/contacts" component={Contacts} />
        </Route>
    );

    ReactDOM.render(
      <Router routes={routes} history={hashHistory} />,
      document.getElementById('app'));
*/

react-router

<Router>

Primary component of React Router.
It keeps your UI and the URL in sync.

Props

children (required)

One or many s or PlainRoutes.
When the history changes, will match a branch of its routes,
and render their configured components, with child route components nested inside the parents.

routes

Alias for children.

history

The history the router should listen to.
Typically browserHistory or hashHistory.

import { browserHistory } from 'react-router'
ReactDOM.render(<Router history={browserHistory} />, el)

createElement(Component, props)

When the router is ready to render a branch of route components,
it will use this function to create the elements.
You may want to take control of creating the elements when you're using some sort of data abstraction,
like setting up subscriptions to stores, or passing in some sort of application module to each component via props.

<Router createElement={createElement} />

// default behavior
function createElement(Component, props) {
  // make sure you pass all the props in!
  return <Component {...props} />
}

// maybe you're using something like Relay
function createElement(Component, props) {
  // make sure you pass all the props in!
  return <RelayContainer Component={Component} routerProps={props} />
}

onError(error)

While the router is matching, errors may bubble up, here is your opportunity to catch and deal with them. Typically these will come from async features like route.getComponents, route.getIndexRoute, and route.getChildRoutes.

onUpdate()

Called whenever the router updates its state in response to URL changes.

render(props)

This is primarily for integrating with other libraries that need to participate in rendering before the route components are rendered.
It defaults to render={(props) => <RouterContext {...props} />}.
Ensure that you render a at the end of the line, passing all the props passed to render.



The primary way to allow users to navigate around your application. <Link> will render a fully accessible anchor tag with the proper href.

A <Link> can know when the route it links to is active and automatically apply an activeClassName and/or activeStyle when given either prop. The <Link> will be active if the current route is either the linked route or any descendant of the linked route. To have the link be active only on the exact linked route, use <IndexLink> instead or set the onlyActiveOnIndex prop.

Props

to

A location descriptor. Usually this is a string or an object, with the following semantics:

  • If it's a string it represents the absolute path to link to, e.g. /users/123 (relative paths are not supported).
  • If it's an object it can have four keys:
    • pathname: A string representing the path to link to.
    • query: An object of key:value pairs to be stringified.
    • hash: A hash to put in the URL, e.g. #a-hash.
    • state: State to persist to the location.

Note: React Router currently does not manage scroll position, and will not scroll to the element corresponding to hash.

activeClassName

The className a <Link> receives when its route is active. No active class by default.

activeStyle

The styles to apply to the link element when its route is active.

onClick(e)

A custom handler for the click event. Works just like a handler on an <a> tag - calling e.preventDefault() will prevent the transition from firing, while e.stopPropagation() will prevent the event from bubbling.

onlyActiveOnIndex

If true, the <Link> will only be active when the current route exactly matches the linked route.

others

You can also pass props you'd like to be on the <a> such as a title, id, className, etc.

Example

Given a route like <Route path="/users/:userId" />:

<Link to={`/users/${user.id}`} activeClassName="active">{user.name}</Link>
// becomes one of these depending on your History and if the route is
// active
<a href="/users/123" class="active">Michael</a>
<a href="#/users/123">Michael</a>

// change the activeClassName
<Link to={`/users/${user.id}`} activeClassName="current">{user.name}</Link>

// change style when link is active
<Link to="/users" style={{color: 'white'}} activeStyle={{color: 'red'}}>Users</Link>


<Route>

A <Route> is used to declaratively map routes to your application's
component hierarchy.

Props

path

The path used in the URL.

It will concat with the parent route's path unless it starts with /,
making it an absolute path.

Note: Absolute paths may not be used in route config that is dynamically loaded.

If left undefined, the router will try to match the child routes.

component

A single component to be rendered when the route matches the URL. It can
be rendered by the parent route component with this.props.children.

const routes = (
  <Route component={App}>
    <Route path="groups" component={Groups} />
    <Route path="users" component={Users} />
  </Route>
)

class App extends React.Component {
  render () {
    return (
      <div>
        {/* this will be either <Users> or <Groups> */}
        {this.props.children}
      </div>
    )
  }
}
components

Routes can define one or more named components as an object of [name]: component pairs to be rendered when the path matches the URL. They can be rendered by the parent route component with this.props[name].

// Think of it outside the context of the router - if you had pluggable
// portions of your `render`, you might do it like this:
// <App main={<Users />} sidebar={<UsersSidebar />} />

const routes = (
  <Route component={App}>
    <Route path="groups" components={{main: Groups, sidebar: GroupsSidebar}} />
    <Route path="users" components={{main: Users, sidebar: UsersSidebar}}>
      <Route path=":userId" component={Profile} />
    </Route>
  </Route>
)

class App extends React.Component {
  render () {
    const { main, sidebar } = this.props
    return (
      <div>
        <div className="Main">
          {main}
        </div>
        <div className="Sidebar">
          {sidebar}
        </div>
      </div>
    )
  }
}

class Users extends React.Component {
  render () {
    return (
      <div>
        {/* if at "/users/123" `children` will be <Profile> */}
        {/* UsersSidebar will also get <Profile> as this.props.children,
            so its a little weird, but you can decide which one wants
            to continue with the nesting */}
        {this.props.children}
      </div>
    )
  }
}
getComponent(nextState, callback)

Same as component but asynchronous, useful for code-splitting.

callback signature

cb(err, component)

<Route path="courses/:courseId" getComponent={(nextState, cb) => {
  // do asynchronous stuff to find the components
  cb(null, Course)
}} />
getComponents(nextState, callback)

Same as components but asynchronous, useful for
code-splitting.

callback signature

cb(err, components)

<Route path="courses/:courseId" getComponents={(nextState, cb) => {
  // do asynchronous stuff to find the components
  cb(null, {sidebar: CourseSidebar, content: Course})
}} />
children

Routes can be nested, this.props.children will contain the element created from the child route component. Please refer to the Route Configuration since this is a very critical part of the router's design.

onEnter(nextState, replace, callback?)

Called when a route is about to be entered. It provides the next router state and a function to redirect to another path. this will be the route instance that triggered the hook.

If callback is listed as a 3rd argument, this hook will run asynchronously, and the transition will block until callback is called.

callback signature

cb(err)

const userIsInATeam = (nextState, replace, callback) => {
  fetch(...)
    .then(response = response.json())
    .then(userTeams => {
      if (userTeams.length === 0) {
        replace(`/users/${nextState.params.userId}/teams/new`)
      }
      callback();
    })
    .catch(error => {
      // do some error handling here
      callback(error);
    })
}

<Route path="/users/:userId/teams" onEnter={userIsInATeam} />
onChange(prevState, nextState, replace, callback?)

Called on routes when the location changes, but the route itself neither enters or leaves. For example, this will be called when a route's children change, or when the location query changes. It provides the previous router state, the next router state, and a function to redirect to another path. this will be the route instance that triggered the hook.

If callback is listed as a 4th argument, this hook will run asynchronously, and the transition will block until callback is called.

onLeave(prevState)

Called when a route is about to be exited.



Histories

React Router is built with history.
In a nutshell, a history knows how to listen to the browser's address
bar for changes and parses the URL into a location object that the
router can use to match routes and render the correct set of components.

You import them from the React Router package:

// JavaScript module import
import { browserHistory } from 'react-router'

Then pass them into your <Router>:

render(
  <Router history={browserHistory} routes={routes} />,
  document.getElementById('app')
)

browserHistory

Browser history is the recommended history for browser application with React Router. It uses the History API built into the browser to manipulate the URL, creating real URLs that look like example.com/some/path.

Configuring Your Server

Your server must be ready to handle real URLs. When the app first loads at / it will probably work, but as the user navigates around and then hits refresh at /accounts/23 your web server will get a request to /accounts/23. You will need it to handle that URL and include your JavaScript application in the response.

An express app might look like this:

const express = require('express')
const path = require('path')
const port = process.env.PORT || 8080
const app = express()

// serve static assets normally
app.use(express.static(__dirname + '/public'))

// handle every other route with index.html, which will contain
// a script tag to your application's JavaScript file(s).
app.get('*', function (request, response){
  response.sendFile(path.resolve(__dirname, 'public', 'index.html'))
})

app.listen(port)
console.log("server started on port " + port)

If you're using nginx, use the try_files directive:

server {
  ...
  location / {
    try_files $uri /index.html;
  }
}

This lets nginx serve static asset files and serves your index.html file when another file isn't found on the server.

There is also a similar approach for Apache servers. Create an .htaccess file in your folder's root:

RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]

IE8, IE9 Support



react-router-redux

history = syncHistoryWithStore(history, store, [options])

Creates an enhanced history from the provided history. This history changes history.listen to pass all location updates through the provided store first. This ensures if the store is updated either from a navigation event or from a time travel action, such as a replay, the listeners of the enhanced history will stay in sync.

You must provide the enhanced history to your <Router> component. This ensures your routes stay in sync with your location and your store at the same time.

The options object takes in the following optional keys:

  • selectLocationState - (default state => state.routing) A selector function to obtain the history state from your store. Useful when not using the provided routerReducer to store history state. Allows you to use wrappers, such as Immutable.js.
  • adjustUrlOnReplay - (default true) When false, the URL will not be kept in sync during time travel. This is useful when using persistState from Redux DevTools and not wanting to maintain the URL state when restoring state.
import React from 'react'
import ReactDOM from 'react-dom'
import { createStore, combineReducers, applyMiddleware } from 'redux'
import { Provider } from 'react-redux'
import { Router, Route, browserHistory } from 'react-router'
import { syncHistoryWithStore, routerReducer } from 'react-router-redux'

import reducers from '<project-path>/reducers'

// Add the reducer to your store on the `routing` key
const store = createStore(
  combineReducers({
    ...reducers,
    routing: routerReducer
  })
)

// Create an enhanced history that syncs navigation events with the store
const history = syncHistoryWithStore(browserHistory, store)

ReactDOM.render(
  <Provider store={store}>
    { /* Tell the Router to use our enhanced history */ }
    <Router history={history}>
      <Route path="/" component={App}>
        <Route path="foo" component={Foo}/>
        <Route path="bar" component={Bar}/>
      </Route>
    </Router>
  </Provider>,
  document.getElementById('mount')
)


push(location), replace(location), go(number), goBack(), goForward()

You must install routerMiddleware for these action creators to work.

Action creators that correspond with the [history methods of the same name]. For reference they are defined as follows:

  • push - Pushes a new location to history, becoming the current location.
  • replace - Replaces the current location in history.
  • go - Moves backwards or forwards a relative number of locations in history.
  • goForward - Moves forward one location. Equivalent to go(1)
  • goBack - Moves backwards one location. Equivalent to go(-1)

Both push and replace take in a [location descriptor], which can be an object describing the URL or a plain string URL.

These action creators are also available in one single object as routerActions, which can be used as a convenience when using Redux's bindActionCreators().

routerMiddleware(history)

A middleware you can apply to your Redux store to capture dispatched actions created by the action creators. It will redirect those actions to the provided history instance.

LOCATION_CHANGE

An action type that you can listen for in your reducers to be notified of route updates. Fires after any changes to history.

posted @ 2016-08-05 14:48  晴明桑  阅读(807)  评论(0编辑  收藏  举报