React-router: A <Link> should not be rendered outside the context of history; some features including real hrefs, active styling, and navigation will not function correctly

Created on 22 Sep 2015  Â·  31Comments  Â·  Source: ReactTraining/react-router

Not sure what this means or how to fix.

Here is the most relevant section of code:

export default class App extends Component {
  render() {
    return (
      <div>
        <Navigation />
        <div id="wrapper" className="container">
          <section id="content">
            <div className="inner">
              <div id="app">
              {this.props.children}
              </div>
            </div>
          </section>
        </div>
      </div>
    );
  }
}

React.render ((
  <Router history={history}>
    <Route path="/" component={App}>
      <IndexRoute component={Dashboard} />
      <Route path="app_catalog" component={AppCatalog}/>
      <Route path="event_viewer" component={EventViewer}/>
    </Route>
  </Router>
bug

Most helpful comment

What about Unit Tests :(

All 31 comments

where are you using <Link>?

AH crud sorry. The <Link>'s are all in the component. Here it is:

import React, {Component} from 'react';
import Router, {Link} from 'react-router';

export default class  Navigation extends Component {
  render() {
    return (
        <header id="main-header">
          <nav className="main-menu navbar navbar-inverse" role="navigation">
            <div className="nav-no-collapse header-nav">

              <ul className="nav navbar-nav navbar-left">
                <li className="dropdown">
                  <a className="dropdown-toggle bb-logo" data-toggle="dropdown" href="#" aria-expanded="false">
                    <div className="bb-logo"></div>
                  </a>

                  <ul className="dropdown-menu">
                  </ul>

                </li>
              </ul>

              <ul className="nav navbar-nav navbar-center">
                <li><Link to="/">Dashboard</Link></li>
                <li><Link to="/app_catalog">App Catalog</Link></li>
                <li><Link to="/event_viewer">Event Viewer</Link></li>
              </ul>
            </div>
          </nav>
        </header>
    );
  }
}

I should add that moving from 0.13.3 to 1.0.0-rc1 today, trying to figure out what all I need to do with this upgrade.

check the Upgrade Guide, looking at this issue now

@jasongonzales23 isn't your issue related to https://github.com/rackt/react-router/issues/1972 ?

I wish I could say if it is related. That issue didn't describe what "This looks to have been an issue with node_modules, sorry about that!" means.

All I did was update react-router from 0.13.3 -> 1.0.0 following the upgrade guide and now things are not working properly (which could be a server config issue because of the new history implementation) and this error.

So I am not seeing how this could be related to my node_modules. Any suggestions? I can post my package.json below to see if anything grabs your attention:

  "dependencies": {
    "babel-core": "^5.0.8",
    "babel-loader": "^5.0.0",
    "body-parser": "^1.12.2",
    "d3": "^3.5.5",
    "es5-shim": "^4.1.0",
    "events": "^1.0.2",
    "flux": "^2.0.1",
    "highcharts": "0.0.9",
    "imports-loader": "^0.6.3",
    "jquery": "^2.1.3",
    "keymirror": "^0.1.1",
    "loader-utils": "^0.2.6",
    "marked": "^0.3.3",
    "moment": "^2.10.6",
    "node-libs-browser": "^0.5.0",
    "object-assign": "^2.0.0",
    "react": "^0.13.1",
    "react-bootstrap": "^0.20.1",
    "react-highcharts": "^2.0.0",
    "react-redux": "^2.1.2",
    "react-router": "1.0.0-rc1",
    "redux": "^3.0.0",
    "sleep": "^3.0.0",
    "superagent": "^1.1.0",
    "webpack": "^1.9.5"
  },
  "devDependencies": {
    "babel-eslint": "^2.0.2",
    "bootstrap-sass": "^3.3.4",
    "bootstrap-sass-loader": "^1.0.3",
    "cli": "^0.6.6",
    "css-loader": "^0.9.1",
    "eslint": "^0.18.0",
    "eslint-plugin-react": "^2.0.2",
    "esprima-fb": "^14001.1.0-dev-harmony-fb",
    "expect": "^1.6.0",
    "expose-loader": "^0.6.0",
    "express": "^4.12.3",
    "file-loader": "^0.8.1",
    "gulp": "^3.8.11",
    "gulp-eslint": "^0.8.0",
    "jscs": "^1.12.0",
    "karma": "^0.12.31",
    "karma-chrome-launcher": "^0.1.12",
    "karma-mocha": "^0.1.10",
    "karma-mocha-reporter": "^1.0.2",
    "karma-sourcemap-loader": "^0.3.4",
    "karma-webpack": "^1.5.1",
    "mocha": "^2.2.4",
    "node-sass": "^2.1.1",
    "react-hot-loader": "^1.3.0",
    "redux-devtools": "^2.1.2",
    "sass-loader": "^0.6.0",
    "style-loader": "^0.9.0",
    "url-loader": "^0.5.5",
    "webpack-dev-server": "^1.8.0"
  }

try rm -rf node_modules && npm install

I've tried to reproduce but it works fine for me, here is my quick example:

import React, { PropTypes, Component } from 'react';
import createBrowserHistory from 'history/lib/createBrowserHistory';
import { Router, Route, Link, IndexRoute } from 'react-router';

class Navigation extends Component {
  render() {
    return (
      <div>
        <ul>
          <li><Link to='/'>Home</Link></li>
          <li><Link to='/inbox'>Inbox</Link></li>
          <li><Link to='/inbox/messages/12' query={{ foo: 'bar' }}>Messages</Link></li>
        </ul>
      </div>
    );
  }
};

class Message extends Component { render() { return <p>Message {this.props.params.id}</p> } };

class Inbox extends Component {
  render() {
    return (
      <div>
        <h2>Inbox</h2>
        {this.props.children || 'Your inbox is empty.'}
      </div>
    );
  }
};

class Home extends Component {
  render() {
    return (
      <div>
        Hello Home
      </div>
    );
  }
}

class App extends Component {
  render() {
    return (
      <div>
        <h1>App</h1>
        <Navigation />

        {this.props.children}
      </div>
    );
  }
}

export default class Root extends Component {
  render() {
    return (
      <Router history={createBrowserHistory()}>
        <Route path='/' component={App}>
          <IndexRoute component={Home} />
          <Route path='inbox' component={Inbox}>
            <Route path='messages/:id' component={Message} />
          </Route>
        </Route>
      </Router>
    );
  }
}

Hrm. Bummer. Stuff is pretty broken and my app really isn't complicated. I don't know if I should file a separate issue, but I cannot get the app to load properly with webpack & hot-loader until I make a trivial change to the code of some kind. How are you serving up your simple example?

I created this https://github.com/knowbody/react-router-playground for myself. Make sure you replace react-router in package.json with the right version. and then you just npm install && npm start to run the "app"

Thanks, playing now!

I've also got this error. It's when i seem to use <Link> inside of a child Component. Do i need to pass the history as a prop to get <Link>'s working in child components?

Same here, and not sure what to do.

Sounds less like a bug and more like a support issue. Try posting your question on stackoverflow with some code samples!

What about Unit Tests :(

+1 for unit tests. I see this warning all the time I try to to test some component that has <Link> in it. Is there a way to suppress this warning?

+1 for unit tests.

For those striving to solve this for unit tests I found solution in form of babel-rewire-plugin.

I reopen this issue as it seems like this might be a bug on our side

Just so people know where this warning is coming from: If you render a <Link> outside a <Router> (or, more specifically, a <RoutingContext>) you'll see this warning message. It's basically telling you that a <Link> needs to know about its history object in order to do anything meaningful.

@mjackson any thoughts on how to do unit testing?

@knowbody +1

@knowbody +1

As far as unit tests, for now I've just been mocking a history context for components that use <Link>. It's not the best solution, but it works as a temporary fix and suppresses all of those warnings. Example:

import MyComponent from '../MyComponent';
import createBrowserHistory from 'history/lib/createBrowserHistory';

// Mock a global context of "history" to suppress warnings from react-router.
MyComponent.childContextTypes = { history : React.PropTypes.object };
MyComponent.prototype.getChildContext = () => ({
  history : createBrowserHistory()
});

// unit tests below, no more errors

Would be nice to have a more "official" workaround.

Nope, no idea how to unit test this. Let's remove the warning.

@mjackson,
I should probably ban myself from git blame, but in the mean time…
https://github.com/rackt/react-router/commit/b86509ae717b4a4f7ebbb80b93e12021147457aa#diff-c7fd3a70340dad9a76157e1ad2e35baaR74
https://github.com/rackt/react-router/commit/b86509ae717b4a4f7ebbb80b93e12021147457aa#diff-c7fd3a70340dad9a76157e1ad2e35baaL80

:trollface:

In the context of this Issue, we're talking about having <Link> in components that we like to Unit Test. We probably need to build up a history context to pass in to the component under test, though is a little annoying.

No need to use git blame, @robcolburn. I wrote just about everything in the modules directory :P

Long story short: If you render your <Link>s inside a <Router> they'll work as they're supposed to. If you don't, they silently won't do anything.

@mjackson awesome! That was not the case in <1.0 - exciting! :dancers:

Uhoh.

Here's a failing test case anyway:

import React, {Component} from "react";
import {Link} from "react-router";

export class MomentListItem extends Component {
  render() {
    const {id, title} = this.props;
    return (
      <div>
        <h2 ref="momentTitle">{title}</h2>
        <p>
          <Link
            ref="momentLink"
            to={`/moments/moment/${id}`}>
            Launch
          </Link>
        </p>
      </div>
    );
  }
}
/*eslint-env mocha*/
import {assert} from "chai";
import React, {Component} from "react";
import {MomentListItem} from "./index";
import testTree from "react-test-tree";

describe("MomentListItem Component", function () {
  var item = testTree(<MomentListItem id={1} title="Woo" />);
  it("should display a title", function() {
    assert.equal(item.momentTitle.innerText, "Woo");
  });
  it("should have a link to the moment", function () {
    console.log(item.momentLink);
    assert.equal(item.momentLink.getAttribute("href"), "/moments/moment/1");
  });
});

@austinpray See 160c5baf67df48ea2f1ef43bb13ce18182de75f2

Hey, is there a way we can provide the history context to a element outside of the router? I'm trying to use semantic UI with a sidebar, but it requires the sidebar to be outside of the app context. I have made the createBrowserHistory() accessible through a global utilities service, and am able to use that outside of the context, but the element itself in the side bar does not work. How can I provide the Link with the history context.

Yes but this is not a good place to ask for help - try Reactiflux or Stack Overflow.

Was this page helpful?
0 / 5 - 0 ratings