How do I navigate to a different route in my react application? - javascript

I want to create new Routes for my works web application, but the way that they are using the Routes is not the way I thought they would be used. Essentially I want to add new routes and be able to click on say like a button, and that will take me to the desired route that I want to go to.
The way it is set up in our application is that you actually have to manually go in the browser and type in the extended path to access that route, which doesn't seem like a good way of doing it.
Right now I have a route set up for our inventory system. You would access this route by typing in localhost::3000/inventory. There are buttons that come up on this main page which when clicked render that specific component. Instead of doing it that way, I would rather set up another route like /additem to the inventory path so that when I click on the Add Item button it will take me to the path localhost::3000/inventory/additem and render that component.
This is what our index.js file looks like for reference
import "babel-polyfill";
import 'core-js/es6/map';
import 'core-js/es6/set';
import 'core-js/fn/array/find';
import 'core-js/fn/array/includes';
import 'core-js/fn/number/is-nan';
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import ServiceReport from './imports/ServiceReportUI/ServiceReport'
import './StyleSheets/ServiceReport.css';
import InventorySystem from './imports/InventorySystem/InventorySystem.js';
import AddNewItemBtn from "./imports/InventorySystem/AddNewItemBtn";
import { BrowserRouter, Route, Link, Switch } from 'react-router-dom'
ReactDOM.render((
<BrowserRouter>
<Switch>
<Route exact path='/' component={App}/>
<Route path='/service' component={ServiceReport} />
<Route exact path='/inventory' component={InventorySystem} />
</Switch>
</BrowserRouter>), document.getElementById('appRoot'));
I'm thinking that adding another route like so will do the trick:
<Route exact path='/inventory/additem' component={AddItem} />
And I would access that route from within my InventorySystem.js file by doing something like this:
Class InventorySystem extends React.Component{
constructor(props){
super(props);
this.state = {}
}
goTo(e){
//go to Add Item path
}
render(){
return(
<button onClick={this.goTo.bind(this)}>Add Item</button>
)
}
}
I don't know much about React Router, and I'm also not sure if this is the right way of going about this, but any help or suggestions would be awesome!

The way to navigate within a React-Router setup is by using the Link component provided by the repo. Your first suggestion to create an additional Route for the AddItem component is correct. Simply import the Link component and define the expected path to go to.
import { Link } from "react-router-dom
class InventorySystem extends React.Component{
constructor(props){
super(props);
this.state = {}
}
render(){
return(
<Link to="/addItem">Add Item</Link>
)
}
}
You can style the Link to look like a button if needed as it does accept a className property.

You have 2 options, both included in example below
import { Link } from "react-router-dom";
class InventorySystem extends React.Component {
constructor(props) {
super(props);
this.state = {}
}
goTo(e) {
// option 1
this.props.history.push('/inventory/additem');
}
render() {
return (
<div>
<button onClick={this.goTo.bind(this)}>Add Item</button> // option 1
<Link to="/inventory/additem">Add Item</Link> // option 2
</div>
)
}
}

Related

How to keep state across different components using React

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?

React-Route redirect after socket.io

I am trying to redirect to another path after receiving some information from the server, but It seems I can only use within , which I am not able to do.
the flow looks like this
1. client send socket message asking for a path
2. server look up a path, and send it back to client
3. client store the path into redux
4. redirect to the path
How can I achieve this?
Here's two ways you can redirect using react-router-dom, here's an example.
I suggest taking a look at the react-router docs here https://reacttraining.com/react-router/web/guides/philosophy
Method 1:
If you have a component that wraps your whole application use render and pass props for its arguments example.
https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/Route.md#render-func
//Wrapping component
import {BrowserRouter as Router, Route} from 'react-router-dom'
//Import your store ex:
{store} from '/path/to/store'
import Child from './components/child'
import Navbar from './components/navbar'
import Footer from './components/footer'
class App extends React.Component {
render() {
return(
<Provider store={store}>
<Router>
<div className="root">
<Navbar />
<Route exact path="/child" render={props => <Child {...props}/>}
//More routes.....
<Footer />
</div>
</Router>
</Provider>
)
}
}
//Child component
class SomeComponent extends React.Component {
constructor(props) {
super(props)
}
componentDidMount() {
socket.on('redirect', url => {
//dispatch your action to update store then redirect
this.props.history.push(url)
})
}
render() {
//some html
}
}
Method 2:
Store the redirect path in the store, and check if not null, you can use middleware, but for this example I'll use a simple if statement inside the component, the drawback using this method is you will need to dispatch an action after the redirect(you may run into some redirect issues if you don't) so it may be useful to wrap the redirect inside a method, and dispatch another action to set it back to null.
import {Redirect} from 'react-router-dom'
class SomeComponent extends React.Component {
render() {
if(this.props.redirectPath) return <Redirect to={this.props.redirectPath} />
else //Render your component
}
}

Images don't show only when optional html parameter is provided (but do show otherwise)

I have parent component that shows an image at a specified path (note: the image is already saved in my project). This path optionally can have additional parameters. If the
For example, The image is displayed (image) if the html path is:
www.mysite.com/myPath
The component is displayed but image is broken (broken image) if the html path is:
www.mysite.com/myPath/someFilterForThisPage
Router
// Libraries
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { browserHistory } from 'react-router';
// Components
import Home from './containers/Home';
import NotFound from './components/NotFound';
import MyComponent from './components/MyComponent';
// Redux
import { Provider } from 'react-redux';
import {createStore} from 'redux';
import allReducers from './reducers';
const store = createStore(
allReducers,
window.devToolsExtension && window.devToolsExtension()
);
// Routes
const routes = (
<Router history={browserHistory}>
<div>
<Provider store={store}>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/myPath/:filter?" component={MyComponent} />
<Route component={NotFound} />
</Switch>
</Provider>
</div>
</Router>
);
export default routes;
I don't think the issue is with my router.js file since the component still shows when a filter is applied in the html path (the image is just broken, ), but I am providing it just in case I am misunderstanding something.
My Component:
// React
import React from 'react';
class MyComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
<div>
<img src={"img/x.png"} id="someId" alt=""/> // ISSUE
// ...
// some divs that show/don't based on the filter of the html path
// ...
</div>
}
}
export default MyComponent;
I have looked at and tried some of the following, but with little luck:
React won't load local images
Dynamically Add Images React Webpack
I think these are different because these are mainly issues related to being unable to display images at all. I am able to display the image, but only when the optional html parameter is not set.
Does anyone know why the image is showing, but only if there is no extra html parameter?
Many thanks.
Any reason why {"img/x.png"} is not accessing root? Such as {"/img/x.png"} or setup your env domain as a global variable and add that in there otherwise you are looking inside every directory you hit for an img directory.

react-router v4 - browserHistory is undefined

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.

reactjs - can not read property push of undefined

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);

Categories