Alex Cushing Alex Cushing - 3 months ago 22
Javascript Question

React not routing on button click

brand new to react so heads up

Im doing the catch of the day tutorial and am on the step where you integrate routes to redirect urls on button clicks. I set it up how the tutorial says:

var React = require('react');
var ReactDOM = require('react-dom');

var ReactRouter = require('react-router');
var Router = ReactRouter.Router;
var Route = ReactRouter.Route;
var History = ReactRouter.History;

var createBrowserHistory = require('history/lib/createBrowserHistory');

var h = require('./helpers');
/*
App
*/

var App = React.createClass({

render : function() {
return (
<div className="catch-of-the-day">
<div className="menu">
<Header tagline="Fresh Seafood Market" />
</div>
<Order/>
<Inventory/>
</div>
)
}
});

/*
Header
<Header/>
*/
var Header = React.createClass({
render : function() {
return (
<header className="top">
<h1>Catch
<span className="ofThe">
<span className="of">of</span>
<span className="the">the</span>
</span>
Day</h1>
<h3 className="tagline"><span>{this.props.tagline}</span></h3>
</header>
);
}
})

/*
Order
<Order/>
*/
var Order = React.createClass({
render : function() {
return (
<p>Order</p>
);
}
})

/*
Inventory
<Inventory/>
*/
var Inventory = React.createClass({
render : function() {
return (
<p>Inventory</p>
);
}
})


/*
StorePicker
This will let us make <StorePicker/>
*/

var StorePicker = React.createClass({
mixins : [History],
goToStore : function(event) {
event.preventDefault();
// get the data from the input
var storeId = this.refs.storeId.value;
this.history.pushState(null, '/store/' + storeId);
},
render : function() {
return (
<form className="store-selector" onSubmit={this.goToStore}>
<h2>Please Enter A Store</h2>
<input type="text" ref="storeId" defaultValue={h.getFunName()} required />
<input type="Submit" />
</form>
);
}

});

/*
Not Found
*/

var NotFound = React.createClass({
render : function() {
return <h1>Not Found! 404</h1>
}
});


/*
Routes
*/

var routes = (
<Router history={createBrowserHistory()}>
<Route path="/" component={StorePicker}/>
<Route path="/store/:storeId" component={App}/>
<Route path="*" component={NotFound}/>
</Router>
)

ReactDOM.render(routes, document.querySelector('#main'));


but it does not redirect on button press, I get this error in my console:


uncaught TypeError: history.push is not a function


Tried to move away from the mixin which is depreciated following the link given to me by @ManoloSantos

this is my updated code which runs with the same error:

var React = require('react');
var ReactDOM = require('react-dom');

var ReactRouter = require('react-router');
var Route = ReactRouter.Route;
var History = ReactRouter.History;
import { Router, useRouterHistory } from 'react-router'
import { createHashHistory } from 'history'
var createBrowserHistory = require('history/lib/createBrowserHistory');
const appHistory = useRouterHistory(createHashHistory)({ queryKey: false })
var h = require('./helpers');
/*
App
*/

var App = React.createClass({

render : function() {
return (
<div className="catch-of-the-day">
<div className="menu">
<Header tagline="Fresh Seafood Market" />
</div>
<Order/>
<Inventory/>
</div>
)
}
});

/*
Header
<Header/>
*/
var Header = React.createClass({
render : function() {
return (
<header className="top">
<h1>Catch
<span className="ofThe">
<span className="of">of</span>
<span className="the">the</span>
</span>
Day</h1>
<h3 className="tagline"><span>{this.props.tagline}</span></h3>
</header>
);
}
})

/*
Order
<Order/>
*/
var Order = React.createClass({
render : function() {
return (
<p>Order</p>
);
}
})

/*
Inventory
<Inventory/>
*/
var Inventory = React.createClass({
render : function() {
return (
<p>Inventory</p>
);
}
})


/*
StorePicker
This will let us make <StorePicker/>
*/

var StorePicker = React.createClass({
contextTypes: {
router: React.PropTypes.object.isRequired
},
goToStore : function(event) {
event.preventDefault();
// get the data from the input
var storeId = this.refs.storeId.value;
this.context.router.push(null, '/store/' + storeId);
},
render : function() {
return (
<form className="store-selector" onSubmit={this.goToStore}>
<h2>Please Enter A Store</h2>
<input type="text" ref="storeId" defaultValue={h.getFunName()} required />
<input type="Submit" />
</form>
);
}

});

/*
Not Found
*/

var NotFound = React.createClass({
render : function() {
return <h1>Not Found! 404</h1>
}
});


/*
Routes
*/

var routes = (
<Router history={appHistory}>
<Route path="/" component={StorePicker}/>
<Route path="/store/:storeId" component={App}/>
<Route path="*" component={NotFound}/>
</Router>
)

ReactDOM.render(routes, document.querySelector('#main'));


THIS FIXED IT:

var React = require('react');
var ReactDOM = require('react-dom');

var ReactRouter = require('react-router');
var Router = ReactRouter.Router;
var Route = ReactRouter.Route;
import { browserHistory, IndexRoute, useRouterHistory } from 'react-router'
import { createHistory } from 'history'
var h = require('./helpers');


const history = useRouterHistory(createHistory)({
basename: '/'
})


/*
App
*/

var App = React.createClass({

render : function() {
return (
<div className="catch-of-the-day">
<div className="menu">
<Header tagline="Fresh Seafood Market" />
</div>
<Order/>
<Inventory/>
</div>
)
}
});

/*
Header
<Header/>
*/
var Header = React.createClass({
render : function() {
return (
<header className="top">
<h1>Catch
<span className="ofThe">
<span className="of">of</span>
<span className="the">the</span>
</span>
Day</h1>
<h3 className="tagline"><span>{this.props.tagline}</span></h3>
</header>
)
}
})

/*
Order
<Order/>
*/
var Order = React.createClass({
render : function() {
return (
<p>Order</p>
)
}
})

/*
Inventory
<Inventory/>
*/
var Inventory = React.createClass({
render : function() {
return (
<p>Inventory</p>
)
}
})


/*
StorePicker
This will let us make <StorePicker/>
*/

var StorePicker = React.createClass({
goToStore : function(event) {

event.preventDefault();
// get the data from the input
var storeId = this.refs.storeId.value;
browserHistory.push('/store/' + storeId);
},
render : function() {
return (
<form className="store-selector" onSubmit={this.goToStore}>
<h2>Please Enter A Store</h2>
<input type="text" ref="storeId" defaultValue={h.getFunName()} required />
<input type="submit" />
</form>
)
}

});

/*
Not Found
*/

var NotFound = React.createClass({
render : function() {
return <h1>Not Found!</h1>
}
});


/*
Routes
*/

var routes = (
<Router history={browserHistory}>
<Route path="/" component={StorePicker}/>
<Route path="/store/:storeId" component={App}/>
<Route path="*" component={NotFound}/>
</Router>
)

ReactDOM.render(routes, document.querySelector('#main'));

Answer

You are using a deprecated way for navigating. In this page you have an upgrade guide to migrate from mixins. I paste here the relevant part.

// v2.0.0
// You have a couple options:
// 1) Use context.router (especially if on the server)
const DeepComponent = React.createClass({
  contextTypes: {
    router: React.PropTypes.object.isRequired
  },
  handleSubmit() {
    this.context.router.push(...)
  }
}

// 2) Use the singleton history
import { browserHistory } from 'react-router'
const DeepComponent = React.createClass({
  handleSubmit() {
    browserHistory.push(...)
  }
}

Edit: It seems that from v2.4 there is a HoC that simplifies the acquisition of the router from the context.

Comments