import React from 'react';
import SearchDocument from './components/searchDocument';
import CreateRequest from './components/createRequest';
import { BrowserRouter as Router } from "react-router-dom";
import { Route, Switch } from 'react-router-dom';
class App extends React.Component {
render() {
return (
<Router>
<div>
<Switch>
<Route exact path='/' component={Home} />
<Route path='/home' component={Home} />
<Route path='/create' component={CreateRequest} />
<Route path='/searchDocument' component{SearchDocument} />
<Route path='/upload' component={UploadDocument} />
<Route path='/search' component={Search} />
</Switch>
</div>
</Router>
);
}
}
export default App;
I am new to react router.I want to pass props through route to create request component.I tried different methods to pass props but that doesn't work.Can anyone please suggest, how to send props to component and how to handle them in that component.Above is my code.Thanks in advance
As mentioned in the comments, you can use the render prop instead of the component.
From the docs:
Instead of having a new React element created for you using the component prop, you can pass in a function to be called when the location matches. The render prop receives all the same route props as the component render prop.
And an example with your code will look like this:
<Route path='/searchDocument' render={(props) => <SearchDocument yourNewProp={yourNewProp} {...props} />} />
Related
Is there a way to pass the location prop and own made prop to another component? I've figured out how to pass DIR_URL through a function like below but I also need to use location prop later in ConfirmAccount component to read pathname property and so on. (Of course in this way it gets true value).
import React, { Component, Fragment } from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Main from './components/structure/Main';
import ConfirmAccount from './components/pages/ConfirmAccount';
import NoMatch from './components/pages/NoMatch';
class App extends Component {
render() {
const url = 'http://localhost:3006';
return (
<Fragment>
<Router>
<Switch>
<Route exact path="/" component={Main} />
<Route path="/confirm">
{/* How can I pass the location? */}
<Route path="/:url" component={() => <ConfirmAccount DIR_URL={url} location />} />
</Route>
<Route component={NoMatch} />
</Switch>
</Router>
</Fragment>
);
}
}
export default App;
React Router DOM automatically passes match location and history props.
You can use the route render prop to pass them manually if you wish:
<Route path="/:url" render={(routeProps) => <ConfirmAccount DIR_URL={url} {...routeProps} />} />
I suggest that you use useHistory hook from ReactRouterDom inside your child component. There you got all the location stuff that you need.
Or pass route properties to rendering component:
import React, { Component, Fragment } from 'react';
import { BrowserRouter as Router, Switch, Route, useHistory } from 'react-router-dom';
import Main from './components/structure/Main';
import ConfirmAccount from './components/pages/ConfirmAccount';
import NoMatch from './components/pages/NoMatch';
class App extends Component {
render() {
const url = 'http://localhost:3006';
return (
<Fragment>
<Router>
<Switch>
<Route exact path="/" component={Main} />
<Route path="/confirm">
{/* How can I pass the location? */}
<Route path="/:url" component={(routeProps) => <ConfirmAccount DIR_URL={url} {...routeProps} />} />
</Route>
<Route component={NoMatch} />
</Switch>
</Router>
</Fragment>
);
}
}
const ConfirmAccount = ({location}) => {
const history = useHistory()
}
export default App;
just import { useLocation } from 'react-router-dom' and use it like this:
const location = useLocation()
now you can access the location object.
read more about it here: https://reactrouter.com/web/api/Hooks/uselocation
or you can use withRouter HOC like this https://reactrouter.com/web/api/withRouter
I'm starting in React and I'm curious about about if have any way to change a page without reload all the html, changing only a content component for example.
I know that there is a way to change the component without change the url but I thought that if the url change too the application would be better.
React Router is the exact thing you're looking for
Here, how you can achieve what you're looking for.
First, wrap your app with BrowserRouter
import { BrowserRouter } from "react-router-dom";
import React from 'react';
class App extends React.Component {
return (){
return (
<BrowserRouter>
<SomeComponent />
</BrowserRouter>
)
}
}
Now just use the Route and Link. Route told the application which component to render on the basis of the current route and Link changes the URL without reloading the whole page
import { Route, Link, Switch } from "react-router-dom";
import React from 'react';
import {Circle, Square} from './someFileWithComponents';
class SomeComponent extends React.Component {
render(){
return (
<div>
<Link to='/circle' >Circle</Link>
<Link to='/square' >Square</Link>
<Switch>
<Route path='/circle' component={Circle} />
<Route path='/square' component={Square} />
</Switch>
</div>
)
}
}
React Router is what you looking for
const AppRouter =()=>(
<BrowserRouter>
<div>
<Header/>//where Header components contains the navigation
<Switch>
<Route path="/" component={BookListPage} exact={true} />
<Route path="/create" component={AddBookItem} />
<Route path="/edit/:id" component={EditBookItem} />
<Route path="/help" component={HelpPage} />
<Route component={NotFoundPage} />
</Switch>
</div>
</BrowserRouter>
);
export default AppRouter;
I am working on a react project. I try to access the url parameters in the Header component. However, it always returns empty.
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import { ConnectedRouter } from 'connected-react-router'
import SamplePage from './pages/SamplePage';
import PropertyPage from './pages/PropertyPage';
import LoadingPage from './pages/LoadingPage';
import Header from './header/Header';
import ButtonGroup from './ButtonGroup';
import { Container } from 'semantic-ui-react';
import history from '../history';
const App = () => {
return (
<ConnectedRouter history={history}>
<div>
<Switch>
<Route path='/loading' exact component={LoadingPage} />
<Route component={Header} title='Sample page' />
</Switch>
<Container style={{ marginTop: '7em' }}>
<Switch>
<Route
path='/page/:pageType/properties/:propertyId'
exact
component={PropertyPage}
/>
<Route path='/page/:pageType' exact component={SamplePage} />
</Switch>
</Container>
<Switch>
<Route exact path='/loading' render={() => <div />} />
<Route component={ButtonGroup} />
</Switch>
</div>
</ConnectedRouter>
);
}
export default App;
I try to access url params in the Header component. The params is empty, and isExact is false. Can anyone help me with this? Thanks.
From screenshot of console.log, react-router is matching on
<Route component={Header} title='Sample Scorecard' />
This is correct behavior as Switch looks for the first match.
I suggest to not declare rendering for Header as a Route. i.e.
<Switch>
<Route path='/loading' exact component={LoadingPage} />
<Header title='Sample Scorecard' />
</Switch>
This way Switch will only render it when loading path isn't matched.
I still cannot figure out how to solve this issue. What I do to walk around this issue is to create a Higher Order Component. Header will be included in the HOC, then it has no problem to get the URL parameters.
I have some nested routes written in react router v4 and in the Navigation component I have an input box.
On submit I need to call a method on a different route (on Landing component) and pass the value. I can't find any example to call a method in Route.
Any other way/ workaround to use a navigation with data and different routes is welcome.
My routes:
return (
<div>
<Navigation callSearch = {this.callSearch.bind(this)} />
<Switch>
<Route path="/u/:slug" component={AuthorPage}/>
<Route path="/:location/:slug" component={PhotoDetails}/>
<Route path="/" component={Landing} />
</Switch>
</div>
)
In Navigation i call callSearch() :
searchPhotos(e) {
e.preventDefault();
if(this.state.searchTerm) {
this.props.callSearch(this.state.searchTerm);
}
}
I have fixed this issue in my application using withRouter from react-router module.
import { Route } from "react-router-dom";
import { withRouter } from "react-router";
class SideBar extends Component {
callSearch = (searchKeyword) => {
if(searchKeyword) this.props.history.push(`/u/${searchKeyword}`);
};
render() {
return (
<div>
<Navigation callSearch = {this.callSearch} />
<Switch>
<Route path="/u/:slug" component={AuthorPage}/>
<Route path="/:location/:slug" component={PhotoDetails}/>
<Route path="/" component={Landing} />
</Switch>
</div>
)
}
export default withRouter(SideBar);
Hope this will help anyone else !!!
Is there a way to nest routes in React Router v4?
This works:
<Router basename='/app'>
<main>
<Route path='/' component={AppBar} />
<Route path='/customers' component={Customers} />
</main>
</Router>
This does not:
<Router basename='/app'>
<Route path='/' component={AppBar}>
<Route path='/customers' component={Customers} />
</Route>
</Router>
Customers Component:
import React, { Component, PropTypes } from 'react'
import styled from 'styled-components'
export default class Customers extends Component {
render () {
return (
<Container>
<h1>Customers</h1>
</Container>
)
}
}
const Container = styled.section`
height: 100%;
padding: 15px;
overflow: auto;
`
Best pattern I have found so far.
// main app
<div>
// not setting a path prop, makes this always render
<Route component={AppShell}/>
<Switch>
<Route exact path="/" component={Login}/>
<Route path="/dashboard" component={AsyncDashboard(userAgent)}/>
<Route component={NoMatch}/>
</Switch>
</div>
I can just keep nesting this inside a component and everything works nice including hmr(If using webpack, dont forget to set output.publicPath to "/")
// dashboard component
<div>
// the same way as before, not setting a path prop
// makes it render on every /dashboard/** request
<Route component={DashboardTAB}/>
<Switch>
// longer path (with same root) than others first
<Route path="/dashboard/graphs/longerpath" component={GraphForm}/>
<Route path="/dashboard/graphs" component={Graphs}/>
<Route path="/dashboard/workers" component={List}/>
<Route path="/dashboard/insert" component={InsertComponent}/>
</Switch>
</div>
I adapted this from the docs, seem to work so far. Probably missing something obvious, and yes it is not the v4 way but we need all the routes defined in one place.
function RouteNest(props){ return (
<Route exact={props.exact} path={props.path} render={ p => <props.component {...p} children={props.children}/> } />
)}
export const MainRoutes = props =>
<div className='content layout'>
<Route exact path="/" component={Landing}/>
<Route path={'/contact'} component={Contact}/>
<RouteNest path={'/thing'} component={CompoWithSub}>
<RouteNest path={'/thing/suba'} component={SubComponentA}/>
<RouteNest path={'/thing/subb'} component={SubComponentB}/>
</RouteNest>
</div>
export const CompoWithSub = props => <div>{props.children)</div>
You're AppBar component is in charge of rendering Customers. For customers to be called, you have to render the children of AppBar. Anything directly nested under AppBar is a child of AppBar.
import React from 'react';
const AppBar = ({ children }) => (
<div>
<header>
<h1> stuff </h1>
</header>
{children}
</div>
);
export default AppBar
Please note that only AppBar will render when you visit "/". AppBar and Customers will render when you visit "/customers".
If someone wants to have nested routes without typing prefix of wrapper route I've created something like this in TSX:
Imports:
import * as React from 'react';
import { Route, RouteComponentProps, RouteProps, Switch } from 'react-router-dom';
import Index from 'views/index';
import Login from 'views/login';
import NoMatch from 'views/no-match';
Interfaces:
interface INestedRoutes {
nested?: string;
}
interface INestedRoute extends RouteProps, INestedRoutes {}
NestedRoute and NestedRoutes wrapper:
class NestedRoutes extends React.Component<INestedRoutes> {
public render() {
const childrenWithProps = React.Children.map(this.props.children, (child) => {
return React.cloneElement(
child as React.ReactElement<any>, { nested: this.props.nested },
);
})
return childrenWithProps;
}
}
const NestedRoute: React.SFC<INestedRoute> = (props: INestedRoute) => {
return <Route path={`${props.nested}${props.path}`} component={props.component} />;
};
And routes with wrapper:
const MultiLanguage: React.SFC<RouteComponentProps<any>> = (props: RouteComponentProps<any>) => {
return (
<NestedRoutes nested={props.match.path} >
<NestedRoute path="/test" component={Login} />
<NestedRoute path="/no-match" component={NoMatch} />
</NestedRoutes>
);
};
export default (
<Switch>
<Route path="/:language" component={MultiLanguage}/>
<Route exact={true} path="/" component={Index} />
<Route path="/login" component={Login} />
<Route component={NoMatch} />
</Switch>
);
For nested routes there is a very simple way which i using.
Example main router is be like that
<Router history={history}>
<Switch >
<Route path="/" component={Home}></Route>
</Switch>
</Router>
Inside Home component using Nested Routing be like:
<div className="App">
<Navbar title="Home" links = { NavbarLinks }/>
{this.renderContentPage()}
</div>
renderContentPage will check the URL and render the nested route.
<Route exact path="/" component={Page1}></Route>
<Route exact path="/page1" component={Page1}></Route>
<Route exact path='/page2' component={Page2} />
So inside Home component page1 and page2 components rendered.
Route expects a single children i.e. a component.
It should not be a new Route.
What you can do is to include your nested routes inside your customers component.
Also make sure to remove exact inside the routes in customers component.