Navigating Programatically

While most navigation happens with Link, you can programatically navigate around an application in response to form submissions, button clicks, etc.

Let's make a little form in Repos that programatically navigates.

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

export default React.createClass({

  // add this method
  handleSubmit(event) {
    event.preventDefault()
    const userName = event.target.elements[0].value
    const repo = event.target.elements[1].value
    const path = `/repos/${userName}/${repo}`
    console.log(path)
  },

  render() {
    return (
      <div>
        <h2>Repos</h2>
        <ul>
          <li><NavLink to="/repos/rackt/react-router">React Router</NavLink></li>
          <li><NavLink to="/repos/facebook/react">React</NavLink></li>
          {/* add this form */}
          <li>
            <form onSubmit={this.handleSubmit}>
              <input type="text" placeholder="userName"/> / {' '}
              <input type="text" placeholder="repo"/>{' '}
              <button type="submit">Go</button>
            </form>
          </li>
        </ul>
        {this.props.children}
      </div>
    )
  }
})

There are two ways you can do this, the first is simpler than the second.

First we can use the browserHistory singleton that we passed into Router in index.js and push a new url into the history.

// Repos.js
import { browserHistory } from 'react-router'

// ...
  handleSubmit(event) {
    // ...
    const path = `/repos/${userName}/${repo}`
    browserHistory.push(path)
  },
// ...

There's a potential problem with this though. If you pass a different history to Router than you use here, it won't work. It's not very common to use anything other than browserHistory, so this is acceptable practice. If you're concerned about it, you can make a module that exports the history you want to use across the app, or...

You can also use the router that Router provides on "context". First, you ask for context in the component, and then you can use it:

export default React.createClass({

  // ask for `router` from context
  contextTypes: {
    router: React.PropTypes.object
  },

  // ...

  handleSubmit(event) {
    // ...
    this.context.router.push(path)
  },

  // ..
})

This way you'll be sure to be pushing to whatever history gets passed to Router. It also makes testing a bit easier since you can more easily stub context than singletons.


Next: Server Rendering