React Router difference between component with and without function - reactjs

const PATH = BASE + '/' + id;
<Route path="PATH" render={PageContainer} /> (DOESN'T WORK for the case below)
<Route path="PATH" component={PageContainer} /> (DOESN'T WORK for the case below)
<Route path="PATH" component={ () => <PageContainer /> } /> (WORKS)
Steps:
1) go to the page BASE/1
2) go back to BASE
3) go to BASE/2
PageContainer connects to the store and passes props to Page.
Why the second approach works, but the first one not?
Update: <Route path="PATH" render={PageContainer} /> (DOESN'T WORK for the case below)

Try accessing it like this:
<Route path="PATH" component={PageContainer} />
There is a difference between component and render props. You can find the answer here:
react router difference between component and render

render — A function that returns a React element. It will be called when the path matches. This is similar to component, but is useful for inline rendering and passing extra props to the element.
PageContainer is a component so should called but not like PageContainer
Change
<Route path="PATH" render={PageContainer} />
To
<Route path="PATH" render={<PageContainer />} />
In your case I recommend you to use component prop instead of render
<Route path="PATH" component={<PageContainer />} />

Related

What is the difference between <Route component={MyComponent} /> and <Route>{MyComponent}<Route />?

I have seen 2 ways to define routes in React:
<Route path="/" component={MyComponent} />
and
<Route path="/">{MyComponent}<Route />
Can anyone explain me the difference between the two?
You should not really use the:
<Route path="/">{MyComponent}<Route />
variant. It will only work if the component is a Function component(if you try to put a class component you will get an error), and only if the component doesn't have hooks inside. Route type definition states that in props.children it recieves a render function that returns a React.ReactNode based on route props (history, match parameters, ...) or directly a React.ReactNode. So you should really use it like this:
<Route path="/"><MyComponent /><Route />
Or if your component need route props (and this is then the same as ):
<Route path="/">{(props) => <MyComponent {...props} />}<Route />
Hope this helps.

React pass an object to the route

I have this set up of my app in the ´app.js´ file I have my routers defined like this inside the render method
<HashRouter>
<StatusToast />
<Switch>
<Route
exact={true}
path="/"
render={props => (
<ImageScene{...props} title="Images & Information Search" />
)}
/>
<Route path="/case/:id/images" component={DetailsScene} />
</Switch>
</HashRouter>
from ImageScene on a table row click, I call a method like this:
this.props.history.push(/case/${id}/images)
this trigger a route and load DetailsScene where I can get the passed in id like this this.props.match.params.id all works without any problem so far.
My question is how can I pass a more than a string (the id) can I pass somehow the whole object to the route?
I have tried to do something like this for 2nd route instead of:
<Route path="/case/:id/images" component={DetailsScene} />
to set up on the ImageScene a method which can expose the selceted object, for now lets just do a simple one like:
export function getSelectedRow() {
return {
title: 'test'
}
}
and than set up the route like:
const object = getSelectedRow();
<Route path="/case/:id/images"
render={props => (<DetailsScene{...props} title={object.title} />
)}
/>
but I cannot make it work... any help would be graet, I'm totally new to react and the whole router.
you could add state to history.push (https://reacttraining.com/react-router/web/api/history) which is available for component being rendered (DetailsScene). Remember to wrap DetailsScene withRouter(...) to have history.location.state available in its props.

How to pass props to react-router 4 components?

Id like to use my app entry point as a global state store. Passing info down to children as props.
Using react-router 4, how can I send prop data down to the rendered components. In a similar fashion to this:
<Route Path=“/someplace” component={someComponent} extra-prop-data={dataPassedToSomeComponent} />
I’ve seen some janky workarounds for older versions of react-router, that appear to be deprecated.
What is the correct way of doing this in v4?
You can pass in a function to the render prop instead of passing in the component directly to the component prop.
<Route path="/someplace" render={() => <SomeComponent props={} />} />
You can read more here.
And to add to the above answer, if you want the routing properties accessible to the component you need to include those. Now when the router activates "SomeComponent", the component will get all the routing props plus the extra param(s) - in this example "param".
<Route path='/someplace' component={(props) => <SomeComponent param="yo" {...props}/>} />
Technically there is 2 ways to do it.
The first one (not the most efficient) is to pass an inline function to the component prop:
<Route
path=“/someplace”
component={(props) => (
<SomeComponent {...props} extra-prop-data={ dataPassedToSomeComponent } />
) />
The second one is the best solution. To prevent create a new component on every render like on the first exemple, we pass the same inline function but this time to the render prop:
<Route
path=“/someplace”
render={(props) => (
<SomeComponent {...props} extra-prop-data={ dataPassedToSomeComponent } />
) />

location.pathname vs router

I am still learning react router v4. and I'd like to know what exactly is the difference between doing this
getting location using
const {
match,
location,
layoutBoxed,
navCollapsed,
navBehind,
fixedHeader,
sidebarWidth,
theme,
} = this.props;
Option 1
if(location.pathname === '/500'){
return <Page500 />
and this
Option 2
<Route path={'/500'} component={Page500} />
As for me, while the first option displays everything properly for me,
the 2nd one i.e. the router one, shows the component in only half the page.
Now, why is that happening?
Option 1 result -->
Option 2 result -->
But the main point--> what is the difference between using location.path name and router
In Option 2 <Route path={'/500'} component={Page500} />
Here you are creating a Route which has a path of /500 and loads a component Page500. This means that when the user navigates to the path specified in the Route, React-Router will render the component where the Route was defined.
In Option 1 ,
if(location.pathname === '/500'){
return <Page500 />
}
the parent component decides when to render the Page500 component, based on the location prop which it receives. This location prop would ultimately be coming from a Route or the withRouter HOC. This is equivalent to
<Route render={(props)=>{
if(props.location.pathname === '/500'){
return <Page500 />;
}else{
return null;
}
}
}
/>
which can also be written as
<Route path={'/500'} component={Page500} />
So to sum it up, you can only do Option 1 if you get the location prop from the parent component, you can define a Route (Option 2) anywhere in the application.
Edit:
If you have all your Routes like
return( <div>
<Route path={'/500'} component={Page500} />
<Route path={'/confirm-email'} component={PageConfirmEmail} />
<Route path={'/lock-screen'} component={PageLockScreen} />
<Route path={'/login'} component={PageLogin} />
<Route path={'/sign-up'} component={PageSignUp} />
<Route path={'/forgot-password'} component={PageForgotPassword} />
<Route path={'/fullscreen'} component={PageFullscreen} />
</div> );
you are running the risk of multiple Routes rendering which might be why you are getting half page render in Option 2. To prevent that from happening and only render the first Route that matches, you should add a Switch
return( <div>
<Switch>
<Route path={'/500'} component={Page500} />
<Route path={'/confirm-email'} component={PageConfirmEmail} />
<Route path={'/lock-screen'} component={PageLockScreen} />
<Route path={'/login'} component={PageLogin} />
<Route path={'/sign-up'} component={PageSignUp} />
<Route path={'/forgot-password'} component={PageForgotPassword} />
<Route path={'/fullscreen'} component={PageFullscreen} />
</Switch>
</div> );
More on Switch can be found at https://reacttraining.com/react-router/web/api/Switch
One of the main features with react router is that you can do stuff such as:
<Route path="/user/:id" component={User} />
and id will be passed into User component.
Ex. /user/bob and /user/jill will both render a User component, but in your componentDidMount you can now fetch the correct user information from your API.
With location.pathname that task becomes more convoluted as #palsrealm mentioned. But first of all, the location prop must be available for this method to work.
There are other features that you would be losing out, but that is the main one I can think of so far. You can check out the Route api documentation here.
EDIT: As for why it is rendering differently, I really can't answer without more context. For example, is the Route wrapped in a Switch component like so:
<Switch>
// Other routes
<Route exact path="/500" component={Page500} />
</Switch>

How to Pass Data Through My React-Router with ReactJS?

I have the following JSON object...
{ name: "Jessie" }
And I want to be able to pass it through my Router so that it can be displayed on my pages. For example, this is my root page...
StaticPage.jsx
export default class StaticPage extends React.Component {
render() {
return (
<div>
<Router history={hashHistory}>
<Route path='/' component={Search} />
<Route path='/favorites' component={Favorites} />
</Router>
</div>
);
}
}
So passing this data to Search, I would imagine might look something like this...
<Route path='/' component={Search} name = {this.props.name}/>
However, nothing gets rendered when I do that. I have researched this quite a bit and understand, from what I've read, that you cannot pass objects through the Router. It's very odd bc Router looks like a traditional React component but does not function as such. None of the explanations of a work around seem clear to me. Could anyone provide me with an example using this code? I am using react-router 3.0. There didn't seem to be any magical solution with 4.0 so I figured I'd ask before upgrading. Thanks!
It's because the component prop of <Route> only renders the component with route props, not your supplied props.
You can use the render or component prop on a <Route> in React Router v4 to pass a function which returns a <Search> element that explicitly passes the name:
<Route path="/" render={() => <Search name={this.props.name} />} />
Or with component:
<Route path="/" component={() => <Search name={this.props.name} />} />
But you should prefer render or else you'll have lots of remounting. If you still plan to use route props, you can also do:
render={routeProps => <Search name={this.props.name} {...routeProps} />}
A whole different approach, one more elegant in my opinion is to use route params and pass the name directly through the URL:
<Route path="/:name" component={Search} />
When you navigate to /Bob, you can access this.props.match.params.name which'll give you "Bob".
It is not a good practice to pass the object data via the routes directly. It is recommended to pass a param such as name or id in this way:
<Route path='/favorites/:name' component={Favorites} />
And retrieve it from your request in the destination.
This is a duplicate issue: Pass object through Link in react router

Resources