How to import or use only child components? - javascript

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.

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

Pass props to react routes

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.

Conditional loading component based on ReactRouter path

I used a React-Router, coded this
<Router>
<div className="app">
<div className="wrapper">
<AppHeaderMain />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/list/" component={List} />
<Route path="/about/" component={About} />
<Route component={NotFound} />
</Switch>
<div className="menu">
<ul>
<li><NavLink exact to="/">List</NavLink></li>
<li><NavLink to="/about/">About</NavLink></li>
</ul>
</div>
</div>
</div>
</Router>
and I have a question, is it possible to load another component based on Rout path, for example:
path="/" - load <AppHeaderMain />
path="/list/" - load <AppHeaderSubpage />
I know I could insert a AppHeader component into each single component but I would like to don't repeat some additional code which would be required to make that.
I mean something like conditional including (loading) component.
Is it a good practice? Maybe I must to do exactly how I wrote: include in each single component?
I think it is a matter of composition. Why not create a factory function. For example:
function routeHandlerWithAppHeader(Component) {
return (props) => (
<div>
<AppHeaderMain />
<Component {...props}/>
</div>;
);
}
And then use:
<Route exact path="/" component={routeHandlerWithAppHeader(Home)} />

Render multiple components in React Router

I'm used to application layouts with multiple yield areas, i.e. for content area and for top bar title. I'd like to achieve something similar in React Router. For example:
<Router>
<Route path="/" component = { AppLayout }>
<Route path="list"
component = { ListView }
topBarComponent = { ListTopBar }/>
</Route>
</Router>
AppLayout:
<div className="appLayout box">
<div className="appLayout topBar">
{ -- display ListTopBar here -- }
</div>
<div className="appLayout content">
{ -- display ListView here -- }
</div>
</div>
Both child components should receive the same props.
How can I approach this?
To passe multiple component you can do like this :
<Route path="groups" components={{main: Groups, sidebar: GroupsSidebar}} />
<Route path="users" components={{main: Users, sidebar: UsersSidebar}}>
See the doc here :
https://github.com/ReactTraining/react-router/blob/v3/docs/API.md#named-components
In v4, according to the docs, you can render multiple components like this:
<Route path='/some-path' render={() =>
<Fragment>
<FirstChild />
<SecondChild />
</Fragment>
} />
Instead of using div's you can use Fragments.
`
<Route path='/some-path' render={props =>
<Fragment>
<Child 1/>
<Child 2/>
</Fragment>
} />
`
You can also use Array in latest versions of React-router-dom;
<Route path="groups" element={[<Component1/>,<Component2/>]} />
Will work just fine.
To render multiple components you can do this:
<Route
path="/EditEmployee/:id"
render={(props) =>
<div>
<NavMenu />
<EditEmployee {...props} />
</div>
}
/>
Here I'm passing parameter to specific conponent.
//this is the simplest method to render multiple components and it works for me
<Router>
<Route path="/">
<ListView />
<ListTopBar />
</Route>
</Router>
<Route path='/' element={<><Header /> <Home /></>} />
This worked for me in the latest react router dom v6
Another method is within the render method of route multiple passed components can be created using react.createElement
<Route render ={(props)=>React.createElement(Component1, {...props}},
React.createElement(Component2, {...props}}/>
What worked for me was to wrap the multiple components in a <Fragment> or a <div> as a parent element.
return (
< Router>
<div className="App" >
<Routes>
<Route path='/'
element={
<Fragment>
< NavBar />
< NewsLetterCard />
< TestimonialsCard />
< ServicesCard />
< ContactsCard />
< Footer />
</Fragment>
}
/>
</Routes>
</div>
</Router>
);
}
For v6, where you are using Routes instead of Switch to render your components. This works:
<Router>
<Routes>
<Route path='/' element={<><Child1/> <Child2/></>} />
</Routes>
</Router>
But for v5, this works:
<Router>
<Switch>
<Route path="/">
<Child1/>
<Child2/>
</Route>
This seem to work for me, I needed to add canvas animation component as background under homepage ("/") only:
import Page from 'pages/Page';
import Blog from 'pages/Blog';
import Post from 'pages/Post';
import Category from 'pages/Category';
import CanvasParticles from 'components/canvas/CanvasParticles';
...
<Routes>
{['/', '/:slug'].map((path, index) => {
return path === '/' ? (
<Route
exact
path={path}
element={[<CanvasParticles />, <Page />]}
key={index}
/>
):(
<Route path={path} element={<Page />} key={index} />
);
})}
<Route exact path="/blog" element={<Blog />}></Route>
<Route path="/blog/:slug" element={<Post />}></Route>
<Route path="/category/:slug" element={<Category />}></Route>
</Routes>
click on this you can view a image v6 feature : this is the simplest method to render multiple components and it works for me
Main Concept is to you should wrap with element
<Route path="/" element={<> </>}
or
wrap with in Fragment
<Route path="/" element={ }

Categories