Nevolgograd
Nevolgograd

Reputation: 321

The context `router` is marked as required in `Link`, but its value is `undefined`

I have a problem with Link. Googled a lot of topics, but I did not get a correct answer. In one discussion, the problem is in the earlier version of the router, in the other in the wrong import of components, in the third the answer was not even announced.

Also, what's with the 'history'?

Versions of the components:

"react": "^15.4",
"react-dom": "^15.4",
"react-router": "^4.1.1",
"react-router-dom": "^4.1.1"

Errors are:

Warning: Failed context type: The context `router` is marked as required in `Link`,
but its value is `undefined`.

and

Uncaught TypeError: Cannot read property 'history' of undefined

The component where Link is used is quite primitive:

import React from 'react';
import { Link } from 'react-router-dom';

export default class Menu extends React.Component {

constructor(props) {
    super(props);
}

render() {
   return (
   <div>
        <ul>
            <li><Link to="/one">1</Link></li>
            <li><Link to="/two">2</Link></li>
            <li><Link to="/three">3</Link></li>
            <li><Link to="/four">4</Link></li>
        </ul>
    </div>
);
}
}

So the component with the router looks like:

import React from 'react';
import { BrowserRouter, Route } from 'react-router-dom'

import Page1 from './Page1';
import Page2 from './Page2';
import Page3 from './Page3';
import Page4 from './Page4';

export default class Routes extends React.Component {

constructor(props) {
    super(props);
}
render() {
    return (
    <BrowserRouter text = {this.props.text}>
        <Route path = "/one"
               render={(props) => (
               <Page1 text = {this.props.text.Page1} {...props} />)} />
        <Route path = "/two"
               render={(props) => (
               <Page2 text = {this.props.text.Page2} {...props} />)} />
        <Route path = "/three"
               render={(props) => (
               <Page3 text = {this.props.text.Page3} {...props} />)} />
        <Route path = "/four"
               render={(props) => (
               <Page4 text = {this.props.text.Page4} {...props} />)} />
    </BrowserRouter>
);
}
}

And the most root component of the App:

import Header from './pages/menu/Header';
import Routes from './Routes';

const texts = require('text.json');
sessionStorage.setItem('lang','UA');

export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
    text: texts.UA
};
this.langHandler = this.langHandler.bind(this);
}

langHandler() {
if (sessionStorage.lang === 'UA') {
    sessionStorage.setItem('lang','RU');
    this.setState({ text: texts.RU })
} else {
    sessionStorage.setItem('lang','UA');
    this.setState({ text: texts.UA })
}
}

render() {
    return (
        <div id="content">
            <Header changeLang = {this.langHandler} 
                    text = {this.state.text.header}/>
            <Routes text = {this.state.text}/>
        </div>
    );
}
}  

In short, the point is that the page always has a rendered Header, and below it, depending on the selected menu item, the corresponding component was rendered.

I will be grateful for any advice.

Upvotes: 13

Views: 12977

Answers (3)

Ignatius Andrew
Ignatius Andrew

Reputation: 8258

You should use <Link> only inside the <Router> tag; if it's outside of it, you will get this error.

 const Links =()=>(
  <nav>
    <Link to="/">Home</Link>
    <Link to="/about">About</Link>
  </nav>  
)

const App=()=>(

          <Links/>  <==== this will throw Error
          <Router>
            <div>
              <Route path="/" component={Home} />
              <Route path="/" component={About} />
           </div>
        </Router>


    )

following is the right way...

const Links =()=>(
  <nav>
    <Link to="/">Home</Link>
    <Link to="/about">About</Link>
  </nav>  
)

const App=()=>(


          <Router>
           <div>
          <Links/>  <==== this will through Error
              <Route path="/" component={Home} />
              <Route path="/" component={About} />
               </div>
        </Router>


    )

Upvotes: 2

Roman
Roman

Reputation: 21775

We presume, that we have the following:

import  { BrowserRouter as StaticRouter, Router, Switch, Route, Link } from 'react-router-dom';
import  createBrowserHistory from 'history/createBrowserHistory';
const   customHistory = createBrowserHistory();

Then, it looks like that it is necessary to wrap every nested block of links with

<Router history={customHistory}>
    <div>
        <Link to={'/.../' + linkName1}>
            {itemName1}
        </Link>
        <Link to={'/.../' + linkName2}>
            {itemName2}
        </Link>
    </div>
</Router>

Upvotes: 1

Simeon Simeonoff
Simeon Simeonoff

Reputation: 146

Your Menu component should be nested inside the BrowserRouter component for the Links to work within this Router context.

Please take a look at the basic sample: https://reacttraining.com/react-router/web/example/basic

Upvotes: 3

Related Questions