Pass props to react routes - javascript

I have a snackbar handler in Main that I want to pass down to each Route component as a prop. How can I achieve this ?
<Router history={browserHistory}>
<Main history={browserHistory}>
<Switch>
<Route path="/comp1" component={comp1} />
<Route path="/comp2" component={comp2} />
<Route path="/comp3" component={comp3} />
<Route path="/comp4" component={comp4} />
</Switch>
</Main>
</Router>

You can pass down props, including bound event handlers, like this in React Router:
<Route exact path={'/:userId/create-project/:projectId'} component={() => {
return (
<ProjectEditor
goToDashboard={this.goToDashboard}
nextProject={this.state.nextProject}
goToProject={this.goToProject}
updateUserProject={api.updateUserProject}
/>
)
}}
/>

You can place your component inside Route and pass here any props.
<Route path="/comp1"><Comp1 myHandler={MyHAndler}/></Route>
Comp1 get all props from Route too.

Related

How to hide/show a component inside another component in ReactJS

I have my application looking something like below..
import FirstComponent from "./components/firstComponent";
import NextComponent from "./components/nextComponent";
import MyProgressComponent from "./components/progressComponent";
class App extends React.Component {
render() {
return (
<Router>
<div>
<MyProgressComponent />
<Route path="/" exact component={FirstComponent} />
<Route path="/nextComponent" component={NextComponent} />
</div>
</Router>
);
}
}
As we can see 'MyProgressComponent' is visible when we navigate between 'http://localhost:3000/' and 'http://localhost:3000/nextComponent' because it is directly nested under Router component in App component. But I want 'MyProgressComponent' to be visible only in 'http://localhost:3000/nextComponent' and hidden in 'http://localhost:3000/'. Any suggestion ?
I can do this by importing 'MyProgressComponent' inside each component wherever required but I don't want to duplicate it in each component.
You can render multiple components using the below syntax
<Route path="/nextComponent" render={() =>
<>
<MyProgressComponent />
<NextComponent />
</>
}
/>
Based on #Crocsx comment you can apply following check on your code.
<Router>
<div>
{this.props.location.pathname === "/nextComponent" ? <MyProgressComponent />: null}
<Route path="/" exact component={FirstComponent} />
<Route path="/nextComponent" component={NextComponent} />
</div>
</Router>
you can use switch provided by router to achieve this.
Something like below should work for you.
<Switch>
<Route exact path="/nextComponent" component={MyProgressComponent} />
</Switch>
<Switch>
<Route path="/" exact component={FirstComponent} />
<Route path="/nextComponent" component={NextComponent} />
</Switch>
more documentation is available here https://reacttraining.com/react-router/web/guides/basic-components

react-router: functions are not valid react child

I noticed a lot of questions has been asked about functions not valid as react child but none fits my case from what I saw.
I use react-router and the error (Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it.)
occurs when I try to use the Es6 class syntax to create my App components.
Here is my code:
import {BrowserRouter as Router, Route, Switch} from 'react-router-dom';
//all other imports are here too
class App extends Component {
render () {
return (
<Router>
<div className="App">
<Header />
<Switch>
<Route path ='/blog/' component={Blog} />
<Route path ='/about/' component={About} />
<Route path ='/register/' component={Register} />
<Route component={Carousel} />
</Switch>
<Route path='/' exact component={Main} />
<Route path='/foreign/' component={Foreign} />
<Route path='/local/' component={Local} />
<Route path='/snacks/' component={Snacks} />
</div>
</Router>
);
}
}
if I change the Es6 class syntax to a function like this,
const App = (
<Router>
<div className="App">
<Header />
<Switch>
<Route path ='/blog/' component={Blog} />
<Route path ='/about/' component={About} />
<Route path ='/register/' component={Register} />
<Route component={Carousel} />
</Switch>
<Route path='/' exact component={Main} />
<Route path='/foreign/' component={Foreign} />
<Route path='/local/' component={Local} />
<Route path='/snacks/' component={Snacks} />
</div>
</Router>
);
It works perfectly. I don't know why this is happening
following Garret Motzner comment I switched the Dom render function from this
ReactDOM.render(App, document.getElementById('root'));
to
ReactDOM.render(<App />, document.getElementById('root'));
and it now work

How to import or use only child components?

For example I have these components
first.js
<div>
<Route path='/' />
<Route path='/first' />
</div>
second.js
<div>
<Route path='/second' />
<Redirect to='/something' />
</div>
And then i have a component that has this
<Switch>
<First>
<Second>
</Switch>
I am using React-Router and Switch does not work if it's child components are not Route. So how does one just strip those divs from first and second components so only things left are the routes?
You can wrap them in fragment like this:
<React.Fragment>
<Route path='/' />
<Route path='/first' />
</React.Fragment>
You can return them in an array:
return [
<Route path='/' key='root' />,
<Route path='/first' key='first' />
]
Note: returning an array is necessary to provide a key props.

How do you route within a route in react

I'm new to react and trying to get this whole routing thing down. I have page which I want to render multiple routes withing.
My main index.js file looks like this:
ReactDOM.render(
<BrowserRouter>
<div>
<Switch>
<Route path="/adminDash" exact component={AdminDashMain}/>
<Route path="/admin/ClientSearch" exact component={ClientDetailsMain}/>
<Route path="/" exact component={LogIn}/>
</Switch>
</div>
</BrowserRouter>
, document.getElementById('root'));
in client search main I have 3 components
class ClientDetailMain extends React.Component {
render() {
return(
<div>
<Header />
<SubHeader username={this.props.match.params.username} />
<Display username={this.props.match.params.username}/>
</div>
);
}
}
export default withRouter(ClientDetailMain);
I'm using <Display/> as a container and inside of that I want to have other route so that a person can go to
/admin/ClientSearch/refined
/admin/ClientSearch/general
/admin/ClientSearch/fixed
I figured out that the /admin/ClientSearch will match regardless so the header and subheader show on all 3 routes, however my routes which are written as:
const Display = () =>{
return(
<div>
<Route path ='/admin/ClientSearch/refined' component={<Refined/>
<Route path ='/admin/ClientSearch/general' component={<General/>
<Route path ='/admin/ClientSearch/fixed' component={<Fixed/>
</div>
)
};
export default withRouter(ClientDisplay);
aren't displaying anything. Is this how I should be writing it? When I link to and of those 3 the header and subheader show up but the components in the individuals routes don't.
For example
'/admin/ClientSearch/fixed' shows the header and subheader but none of its own components.
They key is in the "exact" attribute of your Routes. In addition, when you create a component that has routes inside, you can get the url of the previous routes through it's props. Like this example:
class Main extends React.Component {
render(){
return (
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/about' component={About} />
<Route exact path='/contact' component={Contact} />
<Route path='/admin' component={AdminArea} />
</Switch>
)
}
}
Then you have your sub-routes like this:
const AdminArea = ({match}) => (
<Switch>
<Route exact path={`${match.url}/specie`} component={Component} />
<Route exact path={`${match.url}/color`} component={Component} />
<Route exact path={`${match.url}/user/:id`} component={Component}/>
</Switch>
)

Attempting to pass a custom attribute into react router (using v4)

I have the following render method in my App.js:
render() {
return (
<LocaleProvider locale={enUS}>
<Router history={history}>
<div>
<Header />
<Switch>
<Route exact path={home} component={requireAuth(Groups)} />
<Route exact path={groups} component={requireAuth(Groups)} />
<Route path={addcard} component={requireAuth(AddCard)} />
<Route path={db} component={requireAuth(DbTbl)} />
<Route component={NoMatch} />
</Switch>
</div>
</Router>
</LocaleProvider>
);
};
And I want to pass in a custom property to the first 2 routes ({home} & {groups}) so I'm attempting to do something like this:
render() {
const groups1 = () => <Groups studyState={this.toggleStudyState}/>;
return (
<LocaleProvider locale={enUS}>
<Router history={history}>
<div>
<Header />
<Switch>
<Route exact path={home} render={requireAuth(groups1)} />
<Route exact path={groups} render={requireAuth(groups1)} />
<Route path={addcard} component={requireAuth(AddCard)} />
<Route path={db} component={requireAuth(DbTbl)} />
<Route component={NoMatch} />
</Switch>
</div>
</Router>
</LocaleProvider>
);
};
But I'm getting this error message from react router:
connectAdvanced.js:3 Uncaught TypeError: Cannot call a class as a
function
So I suspect react router doesn't like the high order component syntax with the render= attribute. How can I pass the studyState attribute into the Groups component being used with the first two tags?
The render property must have a function passed to it. You are giving a Class.
Write something like that:
<Route exact path={home} render={(routerProps) => {
const AuthGroups = requireAuth(Groups);
return <AuthGroups studyState={this.toggleStudyState}/>;
}} />
As I don't know how the requireAuth works, I don't know if the studyState property will be properly passed to the Group component. But I guess it will.
Now to have a cleaner code (if the above solution works):
renderAuthGroups(routerProps) {
const AuthGroups = requireAuth(Groups);
return <AuthGroups studyState={this.toggleStudyState}/>;
}
render() {
return (
<LocaleProvider locale={enUS}>
<Router history={history}>
<div>
<Header />
<Switch>
<Route exact path={home} render={this.renderAuthGroups.bind(this)} />
<Route exact path={groups} render={this.renderAuthGroups.bind(this)} />
<Route path={addcard} component={requireAuth(AddCard)} />
<Route path={db} component={requireAuth(DbTbl)} />
<Route component={NoMatch} />
</Switch>
</div>
</Router>
</LocaleProvider>
);
};

Categories