0
votes

I am getting the error cannot read property history but I defined it.

This used the work when I had it in main.jsx in my client folder but now it stops working.

The app file is in my imports folder.

import { Router, Route, Switch, Redirect } from "react-router-dom";
import createBrowserHistory from "history/createBrowserHistory";

const history = createBrowserHistory();

// App component - represents the whole app
export class App extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <div className="container">

        <Router history={history}>
          <Switch>
            <Route path="/" exact component={Home} />
            <Route
              path="/dashboard"
              render={() =>
                this.props.currentUser ? <Dashboard /> : <NoPermission />}
            />
            <Route path="/test" component={Test} />
            <Route component={NotFound} />
          </Switch>
        </Router>
      </div>
    );
  }
}

more info:

import createBrowserHistory from "history/createBrowserHistory";

within that file createBrowserHistory is the default export.

export.default = createBrowserHistory;

When trying BrowserRouter instead of router and deleting the history const and props I get following error in my console.

modules.js:26944 Uncaught TypeError: Cannot read property 'history' of undefined
    at Link.render (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:26944)
    at modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:18399
    at measureLifeCyclePerf (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:17679)
    at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:18398)
    at ReactCompositeComponentWrapper._renderValidatedComponent (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:18425)
    at ReactCompositeComponentWrapper.performInitialMount (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:17965)
    at ReactCompositeComponentWrapper.mountComponent (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:17861)
    at Object.mountComponent (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:10622)
    at ReactDOMComponent.mountChildren (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:16977)
    at ReactDOMComponent._createInitialChildren (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:14176)

When using BrowserRouter in my main.jsx I can get it working. I can change URL's but the new views do not render. So I think there still is something wrong with the history. In this case I have not defined it but I am not receiving any errors. Any way how I can check or fix this?

import React from "react";
import { Meteor } from "meteor/meteor";
import { render } from "react-dom";
import "../imports/startup/accounts-config.js";

import App from "../imports/layouts/App.jsx";
import Test from "../imports/Test.jsx";
import { BrowserRouter } from "react-router-dom";

Meteor.startup(() => {
  render(
    <BrowserRouter>
      <App />
    </BrowserRouter>,
    document.getElementById("render-target")
  );
});

Going further on Kyle's answer I added withrouter to my test component.

import React, { Component } from "react";
import PropTypes from "prop-types";
import { withRouter } from "react-router";

class Test extends Component {
  static propTypes = {
    match: PropTypes.object.isRequired,
    location: PropTypes.object.isRequired,
    history: PropTypes.object.isRequired
  };

  render() {
    const { match, location, history } = this.props;

    return (
      <div>
        <p>This is a test</p>
        <p>
          You are now at {location.pathname}
        </p>
      </div>
    );
  }
}

export default withRouter(Test);

I am using NavLinks to link to this route in my navigation bar component.

   <NavLink to="/test" activeClassName="active">
          Test
        </NavLink>

However clicking those links does not render the test page. (the address in the URL bar does change). When I press refresh in the browser the page loads and the location.pathname shows the proper location.

If I remove the withrouter the functionality is the same.

I got it working by not using a component to nest the router in. If somebody can explain me why I would greatly appreciate it.

import Navbar from "../components/Navbar.jsx";
import AccountsUIWrapper from "../components/AccountsUIWrapper.jsx";

//import pages
import Home from "../pages/Home.jsx";
import Dashboard from "../pages/Dashboard.jsx";
import Test from "../Test.jsx";
import NotFound from "../pages/NotFound.jsx";
import NoPermission from "../pages/NoPermission.jsx";

let currentUser = Meteor.user();

const App = () =>
  <Router>
    <div>
      <Navbar currentUser={currentUser} />

      <AccountsUIWrapper />

      <p>
        {currentUser ? currentUser._id : "current user id not found"}
      </p>

      <Switch>
        <Route exact path="/" component={Home} />
        <Route
          path="/dashboard"
          render={() => (currentUser ? <Dashboard /> : <NoPermission />)}
        />
        <Route path="/test" component={Test} />
        <Route component={NotFound} />
      </Switch>
    </div>
  </Router>;

export default App;
1
is createBrowserHistory the default export in history/createBrowserHistory?zim
Would need to see some structure - Specifically where is history/createBrowserHistory in relation to this file and as @zim said, is it the default export? (if not, wrap createBrowserHistory like this in imports { createBrowserHistory })Spencer
Like @zim and said, you need to check for the export in history/createBrowserHistory. OR Instead of importing Router, import BrowserRouter and then you wouldn't need the history prop.Giri
I checked and the answers are in the first post. The history file is in my node_modules folder.Christoph
@Christoph What version of react-router are you using?Kyle Richardson

1 Answers

1
votes

React Router 4 has history baked into it. You can see from the documentation for BrowserRouter, HashRouter, and MemoryRouter that there is no argument for history.

If you would like to access history in React Router v4 you should use the withRouter HoC on the component that you wish to have access to it in. withRouter will make ({match, history, location }) available inside any component that it wraps.

As you can see from this line of code: var _createBrowserHistory = require('history/createBrowserHistory'); which is line 13 in BrowserRouter.js and HashRouter.js history is already included for you. It is also included in the memory router on line 9 of MemoryRouter.js.

Try changing your import at the top to import { BrowserRouter as Router, Route, Switch, Redirect } from "react-router-dom"; and then remove history={ history } from <Router />.

EDIT: Please take a look at the documentation for React Router 4. Here is a basic example.

Here is a post of the code incase the link ever goes dead.

import React from 'react'
import {
  BrowserRouter as Router,
  Route,
  Link
} from 'react-router-dom'

const BasicExample = () => (
  <Router>
    <div>
      <ul>
        <li><Link to="/">Home</Link></li>
        <li><Link to="/about">About</Link></li>
        <li><Link to="/topics">Topics</Link></li>
      </ul>

      <hr/>

      <Route exact path="/" component={Home}/>
      <Route path="/about" component={About}/>
      <Route path="/topics" component={Topics}/>
    </div>
  </Router>
)

const Home = () => (
  <div>
    <h2>Home</h2>
  </div>
)

const About = () => (
  <div>
    <h2>About</h2>
  </div>
)

const Topics = ({ match }) => (
  <div>
    <h2>Topics</h2>
    <ul>
      <li>
        <Link to={`${match.url}/rendering`}>
          Rendering with React
        </Link>
      </li>
      <li>
        <Link to={`${match.url}/components`}>
          Components
        </Link>
      </li>
      <li>
        <Link to={`${match.url}/props-v-state`}>
          Props v. State
        </Link>
      </li>
    </ul>

    <Route path={`${match.url}/:topicId`} component={Topic}/>
    <Route exact path={match.url} render={() => (
      <h3>Please select a topic.</h3>
    )}/>
  </div>
)

const Topic = ({ match }) => (
  <div>
    <h3>{match.params.topicId}</h3>
  </div>
)

export default BasicExample