I have this code. What I want to do is when I click a button 'feature' it will take me to index route. However, React keeps saying 'can not read property push of undefined' What I've done wrong?
route.js
import React from "react";
import ReactDOM from "react-dom";
import {Router, Route, hashHistory, IndexRoute } from "react-router";
import Layout from "./page/Layout";
import Features from "./page/Features";
import Features from "./page/archive";
const app = document.getElementById('app');
ReactDOM.render(
<Router history={hashHistory}>
<Route path="/" component={Layout}>
<IndexRoute component={Features} />
<Route path="archive" component={Archive} />
</Route>
</Router>, app);
Layout component
import React from "react";
import {Link, Router, Route, hashHistory} from "react-router";
export default class Layout extends React.Component{
navigate(){
this.context.router.push('/');
}
render(){
return(
<div>
{this.props.children}
<button onClick={this.navigate.bind(this)}>feature</button>
</div>
)
}
}
package.json - partial
"react": "^0.14.7",
"react-dom": "^0.14.7",
"react-router": "^2.0.1"
"history": "^2.0.1",
-------------update to jordan's answer-------------
In React Router v4, you no longer have to give a history to your router. Instead you just use BrowserRouter or HashRouter from 'react-router-dom'. But that makes it unclear how to push a rout to your history when you aren't in a react component.
The solution is to use the history package.
Just import createHistory like this:
import createHistory from 'history/createBrowserHistory'
Or the way I do it is like this:
import { createHashHistory } from 'history'
then create your history
export const history = createHashHistory()
and now you can push to it:
history.push('/page')
I hope this helps others who come to this question. None of the current answers gave me what I needed.
This may not be referring to above example but I had the same error. After lot of debugging I figured out that history is not reachable to my inner components. Make sure your history is reachable.
//main.js
<BrowserRouter>
<div>
<Route path="/" component={Home}/>
<Route path="/techMap" component={TechMap}/>
</div>
</BrowserRouter>
//app.js
<div>
<TechStack history= {this.props.history}/>
</div>
//techstack.js
<div>
<span onClick={this.search.bind(this)}>
</span>
</div>
)
search(e){
this.props.history.push('/some_url');
}
TechStack is my inner component.
Earlier I was able to get history in app.js but not in tech.js.
But after passing props in form of history, I got the history in tech.js and routing works
With React router v4, you need to wrap the components in withRouter. Then you can access history in your components. Do the following:
import { withRouter } from 'react-router-dom';
...
...
export default withRouter(MyComponent);
You need to change your route.js page to
import {Router, browserHistory} from 'react-router';
ReactDOM.render(
<Router history={browserHistory}>
<Route path="/" component={Layout}>
<IndexRoute component={Features} />
<Route path="archive" component={Archive} />
</Route>
</Router>, app);
And then everywhere you want to navigate you can use
import {Router, browserHistory} from 'react-router';
browserHistory.push('/');
The react-router docs encourage you to use browserHistory instead of hashHistory
hashHistory uses URL hashes, along with a query key to keep track of
state. hashHistory requires no additional server configuration, but is
generally less preferred than browserHistory.
usually, when you are trying to redirect from a nested component it will give this error.
there are a few ways to fix it
Using react-dom you can import the withRouter component from react-router-dom then use it as usual with this.props.history.push and instead of the usual export default 'class' we will use export default withRouter(class); and boom problem solve.
I use browserHistory instead of HashHistory.
Then I just need to do the following:
import { browserHistory } from 'react-router'
// ...
// ...
navigate(){
browserHistory.push('/');
}
You don't need to use browserHistory anymore.
React-router-dom inject into your component route related props and context.
One of this props is 'history' and on this history object is a function push that you can call and pass the route you want to navigate to.
example in a Class base component, you can create a function like below as an onClick handler to redirect to specific link
redirectToPage() {
this.props.history.push('/page'); OR
this.context.router.history.push('/page');
}
while in a function base stateless component
redirectToSessionStatePage() {
props.history.push('/page');OR
context.router.history.push('/page');
}
Change your Layout component to have navigate assigned to ES6 lambda. This is needed to set the correct value of this
import React from "react";
import {Link, Router, Route, hashHistory} from "react-router";
export default class Layout extends React.Component{
navigate = () => {
this.context.router.push('/');
}
render(){
return(
<div>
{this.props.children}
<button onClick={this.navigate.bind(this)}>feature</button>
</div>
)
}
}
export default class Layout extends React.Component{
navigate = () => {
this.context.router.push('/');
}
render(){
return(
<div>
{this.props.children}
<button onClick={this.navigate.bind(this)}>feature</button>
</div>
)
}
}
Layout.contextTypes = {
router: PropTypes.object.isRequired
}
It looks like you overwrote your Features import with whatever is in your /archives directory. In the code you posted, you have this:
import Features from "./page/Features";
import Features from "./page/archive";
import {withRouter} from 'react-router-dom';
export default withRouter(AppName);
Related
I'm newbie in reactjs, I tried build something with it but I had problem with react-router-redux. I get React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. in console. Here is my code :
App.js
import React, { PropTypes } from 'react';
class App extends React.Component {
render() {
return (
<div>
{this.props.children}
</div>
);
}
}
export default App;
Routes.js
import React from 'react';
import { Route, IndexRoute } from 'react-router'
import App from './components/App';
import Login from './components/login/Login';
import Register from './components/register/Register';
export default (
<Route path="/" component={App}>
<IndexRoute component={Login}/>
<Route path="register" component={Register}/>
</Route>
);
And Index.js
...
import { syncHistoryWithStore } from 'react-router-redux'
import { Router } from 'react-router'
import { createBrowserHistory } from 'history';
import routes from './routes';
const store = configureStore();
const history = syncHistoryWithStore(createBrowserHistory(), store)
ReactDOM.render(
<Provider store={store}>
<Router history={history} routes={routes}>
</Router>
</Provider>,
document.getElementById('app')
);
Where is my wrong? Please explain for me why I get this error. Thank in advance
React-router-redux is no longer maintained and support only 3.x and 2.x React-router versions
Repo authors suggest using connected-react-router for React-rotuer 4.x bindings
There are different routers for different environments, you want to use BrowserRouter instead of Router.
See React Training BrowserRouter for more information.
index.js
// change this line
import { Router } from 'react-router';
// to
import { BrowserRouter as Router } from 'react-router-dom';
NOTE: You might also have to pass in your routes in a different way. This is shown in the React Training page provided above.
I have three components and navigating between them I am using react routes.
import React from "react";
import {HashRouter, Route, Switch, Redirect} from 'react-router-dom';
import Main from './components/main/main.component';
import SecondView from './components/secondview/secondview.component';
import ThirdView from './components/thirdview/thirdview.component';
import Traineeship from './components/traineeship/traineeships.component';
import InformationFilter from "./components/information/information-filter.component";
import InformationJob from "./components/information/information-job.component";
const AppRoutes = () => (
<HashRouter>
<Switch>
<Route path='/information-filter' component={InformationFilter}/>
<Route path='/information-job' component={InformationJob}/>
<Route path='/traineeships' component={Traineeship}/>
</Switch>
</HashRouter>
);
export default AppRoutes;
In InformationFilter Component I use Link to navigate to the other component liek this:
<Link to={{
pathname: '/information-job',
state: {industry: this.state.selectedIndustry, job: this.state.selectedJob}
}}>
I can see the parameters available into InformationJob and from Information Job I pass sameway using Link into Traineeship but the problem is when I go back from Traineeship this part within InformationJob:
componentDidMount() {
console.log(this.props.location.state);
}
is empty, what is the best way so that I can pass parameters from component A to B then to C so I dont have any problem when clicking back button.
Any idea about this?
I am trying to set a basic example of react router where I have two simple routes, greetings and signup, under a template setup. Currently, I am not getting any errors on load, however, when trying to access the /signup route by typing it in to the address bar, I am getting the following error: Cannot GET /signup and I am having trouble understanding why.
Did anyone else run into this issue with react-router-dom v4? I appreciate any suggestions on how to resolve this issue and allow the successful navigation to different paths via URL.
Note, if I try to access these url paths using the built in react Link component and clicking on the link, its works as expected, but when refreshing the page at the url, I get the Cannot GET signup error again.
app.js
import React from "react";
import NavigationBar from '../components/navigation-bar';
export class App extends React.Component {
render() {
return (
<div className="container">
<NavigationBar />
{this.props.children}
</div>
);
}
}
index.js
import React from 'react';
import ReactDOM from "react-dom";
import {Provider} from "react-redux";
import {createStore} from "redux";
import allReducers from "./reducers";
import {BrowserRouter as Router, Route, Switch} from "react-router-dom";
import {App} from "./components/app";
import {Greetings} from "./components/greetings";
import {Signup} from "./components/signup";
const store = createStore(allReducers);
ReactDOM.render(
<Provider store={store}>
<Router>
<App>
<Switch>
<Route exact path="/" component={Greetings} />
<Route path="/signup" component={Signup} />
</Switch>
</App>
</Router>
</Provider>, window.document.getElementById("app"));
greetings.js
import React from "react";
export class Greetings extends React.Component {
render() {
return (
<h2>
Greetings
</h2>
);
}
}
signup.js
import React from "react";
export class Signup extends React.Component {
render() {
return (
<h2>
SIGN UP
</h2>
);
}
}
Try using HashRouter over BrowserRouter because to use BrowserRouter web server must be ready to handle real URLs.
import {HashRouter as Router, Route, Switch} from "react-router-dom";
I am creating my first react app in electron (my first electron app too). I have two routes & need to navigate from one to another. For that I am using following code:
Root
ReactDOM.render(
<Router history={browserHistory}>
<App />
</Router>,
document.getElementById('root')
);
App
class App extends React.Component {
constructor() {
super();
}
render() {
return (
<div className="app-master">
<Switch>
<Route path='/city' component={CityList}/>
<Route path='/' component={SplashScreen}/>
</Switch>
</div>
)
}
}
Page
import { browserHistory } from 'react-router';
...
browserHistory.push('/city');
This line gives error,
TypeError: Cannot read property 'push' of undefined
I searched web for possible solution but can't find one! There are many similar questions on SO too, but none of it worked for me :(
You have to import it from the history module now which provides 3 different methods to create different histories.
createBrowserHistory is for use in modern web browsers that support the history API
createMemoryHistory is used as a reference implementation and may also be used in non-DOM environments, like React Native or tests
createHashHistory for legacy web browsers
You cannot use the browser history in an electron environment, use the hash or the memory one.
import { createHashHistory } from 'history'
const history = createHashHistory()
You can then use the history injected in the props
this.props.history.push('/')
Useful pointers above. The simplest solution I've found is to add:
import {createBrowserHistory} from 'history';
to your list of import statements, then add:
const browserHistory = createBrowserHistory();
Might not work perfectly, but for the basic stuff I'm working on seems to do the trick. Hope that helps.
Its is not working for your because in your component you are still using browserHistory which is not longer availabe from react-router package. You should change to using history from the history package
To simplify you can create a history.js file with the following contents
import { createBrowserHistory } from 'history'
export default createBrowserHistory();
Root
import history from '/path/to/history';
ReactDOM.render(
<Router history={history}>
<App />
</Router>,
document.getElementById('root')
);
Page
import history from 'path/to/history';
...
history.push('/city');
import { browserHistory } from 'react-router' does not work in React router 4. Link
Use the redirect component:
import { Redirect } from 'react-router';
<Redirect push to="/somewhere/else"/>
The render function should replace the entire content with Redirect component.
In react-router v4 initialize router as constant config and access the history through this.props in child components.
Import you dependecies
import { Route, Router } from "react-router";
import { createBrowserHistory } from "history";
Define your router config and add history as prop
const history = createBrowserHistory();
const routes = (
<Router history={history}>
<Route path='/city' component={CityList}/>
<Route path='/' component={SplashScreen}/>
</Router> )
class App extends Component {
render() {
return (
<div className = "app-master>
{routes}
</div>)
}
Defining route as a constant and out of render method this would initialize the route config only once.
Page Component
class Page extend Component {
render() {
this.props.history.push('/');
}
}
The history is now available as props in all the child components defined in routes config.
Trying to use react router v4 with redux and running into this error, seem to be following the docs, couldn't find any information anywhere on it so I'm at a loss:
Uncaught TypeError: Cannot read property 'route' of undefined
Here's my code:
import React, {Component} from 'react';
import {
BrowserRouter as Router,
Route,
Link,
withRouter
} from 'react-router-dom'
import Menu from './Menu';
import { connect } from "react-redux";
import Play from './Play';
class Manager extends Component {
render() {
return(
<Router>
<div>
<Route exact path="/" component={Menu}/>
<Route path="/menu" component={Menu}/>
<Route path="/play" component={Play}/>
</div>
</Router>
)
}
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Manager));
and here's the full error:
game.js:26838 Uncaught TypeError: Cannot read property 'route' of undefined
at Route.computeMatch (game.js:26838)
at new Route (game.js:26815)
at game.js:15322
at measureLifeCyclePerf (game.js:15102)
at ReactCompositeComponentWrapper._constructComponentWithoutOwner (game.js:15321)
at ReactCompositeComponentWrapper._constructComponent (game.js:15307)
at ReactCompositeComponentWrapper.mountComponent (game.js:15215)
at Object.mountComponent (game.js:7823)
at ReactCompositeComponentWrapper.performInitialMount (game.js:15398)
at ReactCompositeComponentWrapper.mountComponent (game.js:15285)
Here,you are using react-router-dom latest version above 4.0.0.
So,there is no Router available. You need to use BrowserRouter in this version.
your code will be
import React, {Component} from 'react';
import {
Switch,
Route,
Link,
withRouter
} from 'react-router-dom'
import Menu from './Menu';
import { connect } from "react-redux";
import Play from './Play';
class Manager extends Component {
render() {
return(<div>
<Switch>
<Route exact path="/" component={Menu}/>
<Route path="/menu" component={Menu}/>
<Route path="/play" component={Play}/>
</Switch></div>
)
}
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Manager));
and use BrowserRouter in your index.js file to render this Component
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render((<BrowserRouter><Manager/></BrowserRouter>), document.getElementById('root'));
change your router to a new react router 4.0 called "react-router-dom"
using npm/yarn install the module "react-router-dom", define your router like so..
don't forget imports.
import { BrowserRouter, Route } from 'react-router-dom';
<BrowserRouter>
<div>
<Route exact path="/" component={Menu}/>
<Route path="/menu" component={Menu}/>
<Route path="/play" component={Play}/>
</div>
</BrowserRouter>
You don't need to use withRouter higher than your actual Router is :)
Just remove it:
export default connect(mapStateToProps, mapDispatchToProps)(Manager);
You will need to use withRouter HOC, if you want to access history information inside the component nested in Route. You can find details here: https://reacttraining.com/react-router/web/api/withRouter
So I was running this off my local server, when I ran it off a webpack server it worked.
I fixed this by moving my <Navigation /> inside my <Router></Router>