Hide parent component in react-router - reactjs

In react router is there a way to have child routes but not display the parent component? I'm trying to display breadcrumbs in my application so I switched to having child routes but I don't want to display the parent component in the way of a 'master/detail' type layout. I just want the child component displayed as if it were navigated to by itself but it seems if you don't include {this.props.children} somewhere in the parent component then then child component never gets rendered.
One hack I've tried is seeing if this.props.children is populated and not displaying the rest of the page in render like
if(this.props.children) {
return (this.props.children)
} else {
return /**rest of render method**/
}
but this feels like a bad solution.

I'm having trouble understanding exactly what you're trying to do, but it seems <IndexRoute> could help you, since that lets you distinguish what you do at /portal vs. /portal/feature
<Route path="/portal" component={ComponentContainingBreadcrumbs}>
<IndexRoute component={ComponentWithRestofRenderMethodFromYourExample} />
<Route path="child1" component={Child1} />
<Route path="child2" component={Child2} />
</Route>

Related

Create Landing page that render something instead of outlet when route is empty

so I'm using React router for a project, and I need to render something on the landing page so it isn't just a blank page. But the component the app renders has an outlet, and I don't want to deal with making it invisible if the route is not empty. There must be a way to make it so the route displays content if there is any on the output and something else if the output is empty. What came to mind is a tertiary conditional, but i don't know how t make it work in this conditions.
The code structure is something like the following:
const App = () => {
return (
<div>
{//Some code that has to display on every page here}
<Outlet />
{//Some code that has to display on every page here}
</div>)
If you read the docs https://reactrouter.com/docs/en/v6/api#outlet
<Outlet>
An <Outlet> should be used in parent route elements to render their child route elements. This allows nested UI to show up when child routes are rendered. If the parent route matched exactly, it will render a child index route or nothing if there is no index route.
More on Index Routes at https://reactrouter.com/docs/en/v6/getting-started/tutorial#index-routes
So, you need to add an index route nested under the route for App.
// assuming the following is your route for App
<Route path="/" element={<App />}>
// add the following index route
<Route index element={
<div>your landing content</div>
} />
</Route>

How can I display nested component with React router?

I’m using the last release of React Router and I want to know what is the best solution to show different component that are nested in a parent component.
I’ll try to explain myself better.
I have a route R with path /r1.
This route loads component A.
Component A has inside others 3 components B, C and D that I should show in the same page with component A only when the user press a specific button in component A.
So I want to be able to add a description in route R to manage this. For example to show component B the router could be /r1/b.
Now I did this with a state variable inside component A but I think should be better if I can use some React Router property.
Thanks
You can create nested routes component, and it will manage nested routes.
export default function NestedRoutes() {
return (
<Switch>
<Redirect exact from={"/r1"} to={`/r1/A`} />
<Route path={`/r1/A`}>
<ComponentA />
</Route>
<Route path={`/r1/B`}>
<ComponentB />
</Route>
// Or to some not found component
<Redirect to="/r1/A" />
</Switch>
);
}
I'm using Switch with my route entries. The problem was that I didn't know how to render a component that I wanted to pass by props to another component.
I added a prop component to my parent component A and in my route I wrote something like this:
<Route path="/r1/hub/A" render={() => <A /> //this render only A
<Route path="/r1/hub/A/B" render={() => <A component={B} /> //this render A with B
In component A I used React.createElement to render component B with others properties that component A has to inject.

React component briefly renders the wrong data

I have a Profile component that checks to see if the user passed in url params. If not, the Profile component will render using the current logged in user. If they did, it will pull that value and use that userid for the Profile form.
Everything renders. And the proper profiles eventually appear, however if the user passes in different userid to view, the form will first render their own Profile...THEN render the passed in user.
I'm fairly confident that it's an issue of the props not being set at the time the first render occurs. My question is how can I prevent this?
I'm using react router 4.0. I setup a parent child component trying to do a conditional render...nothing seems to help.
My parent render function looks like this:
{this.props.match.params.userId && (
<ProfileForm
key={this.props.match.params.userId}
profileId={this.props.match.params.userId}
/>
)}
{!this.props.match.params.userId && <ProfileForm />}
My Route statement is this:
<Route exact={true} path={routes.PROFILE} component={Profile} />
<Route path={`${routes.PROFILE}/:userId`} component={Profile} />
Is there a way to prevent it from loading the "non-propped" version first or do I have to create a new component for "others" and have the route go there first?

Passing data through React Router to components

I'm struggling to do anything with react/redux.
One of my last challenges was to pass some data from Child Component to Parent Component. I couldn't get the child props by calling parentComponent.props.children.props (I also tried converting children to Array with React.Children.toArray) and then I found a solution for my specific problem reading some data that comes with React Router.
I managed to find out the child component by calling this.props.location.pathname in Parent Component.
I have a Routing structure as following
<Router history={history}>
<Route path="/main" component={Main}>
<Route path="something" component={Something} />
</Route>
</Router>
I wonder if it is possible to pass some data to Main in this declaration. Something like:
<Route path="something" component={Something} data={foo: 'myData'} />
And get foo in the Main.render
Is there something close to this?
You could pass 'myData' as a query parameter. This is my personal preference for passing props to a component using React Router. Then when you browse to /main/something?foo=myData, you can access foo from this.props.location.query.foo.
Any props you pass to the route definition is accessible under the route node in the props. In your Something component, should be able to get the data prop with this.props.route.data

How can I use react-router to trigger state changes?

I'm still coming to grips with React and react-router, but I'm wondering how to use react-router to simply update application state without re-rendering DOM nodes.
For example, suppose I have:
<Router history={browserHistory}>
<Route path="/" component={App}>
<IndexRoute screen="main" />
<Route path="settings" screen="sync" />
<Route path="overview" screen="overview" />
</Route>
</Router>
I'd like to re-use react-router's matching but simply update the App component's current screen.
The reason is that suppose in the above example I have three screens arranged horizontally with only one visible at a time. When the route changes I want to animate in the appropriate screen. If I do that by assigning a component to each route, react-router doesn't render the other screens until the route matches, and there's a noticeable lag for the screen to slide in.
However, if I keep all three screens in the DOM and simply toggle state to trigger CSS transitions there is no lag (since, with appropriate use of will-change, the browser can pre-render the off-screen layer).
I've tried half a dozen ways of achieving this but they're all very hacky or involve duplicating the matching code somewhat. What am I doing wrong?
Also, I'd like to avoid adding something like Redux just to fix this if possible.
So you want something similar to Spectacle?
In your case I would place all the screens as children of the App component, and use react-router's params to know which screen you're on.
<Route path="/(:screen)" component={App}>
It will be avaialble as a prop to the App component:
class App extends React.Component {
componentWillMount () {
this.props.params.screen
}
}
More about route params at react-router/injected-props
If you're having trouble with re-rendering you can use the component lifecycle method shouldComponentUpdate. Returning false in this method will prevent the component from re-rendering and you'll have the new props (which also include the route params).
class App extends React.Component {
shouldComponentUpdate (nextProps) {
nextProps.params.screen
return false
}
}

Resources