Here is my App.js from my current project , I am facing an issue, whenever I render all my components individually which are mentioned in the commented part it gives me complete output, but as soon as I render it through the react-router-dom the page turns blank. Please help me with this.
import Topbar from "./components/topbar/Topbar";
import Homepage from "./pages/homepage/Homepage";
import Login from "./pages/login/Login";
import Register from "./pages/register/Register";
import Settings from "./pages/settings/Settings";
import Single from "./pages/single/Single";
import Write from "./pages/write/Write";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Header from "./components/header/Header";
import Posts from "./components/posts/Posts";
function App() {
const currentUser = true;
return (
// <>
// <Topbar/>
// <Header/>
// <Single/>
// <Homepage/>
// <Posts/>
// <Register/>
// <Login/>
// <Settings/>
// </>
<BrowserRouter>
<Topbar />
<Routes>
<Route exact path="/">
<Homepage />
</Route>
<Route path="/posts">
<Homepage />
</Route>
<Route path="/register">
{currentUser ? <Homepage /> : <Register />}
</Route>
<Route path="/login">{currentUser ? <Homepage /> : <Login />}</Route>
<Route path="/post/:id">
<Single />
</Route>
<Route path="/write">{currentUser ? <Write /> : <Login />}</Route>
<Route path="/settings">
{currentUser ? <Settings /> : <Login />}
</Route>
</Routes>
</BrowserRouter>
);
}
export default App;
Try changing your routes to look something like this:
<Route exact path="/" element={<Homepage />} />
The component you want to render should be in the element prop.
https://reactrouter.com/docs/en/v6/getting-started/overview
https://reactrouter.com/docs/en/v6/upgrading/v5
<Route exact path="/" element={<Homepage />} />
The only time you can put something inside a Route as a child element is for nested routing. For example:
<Route path="/teams" element={<Teams />}>
<Route path=":teams" element={<Team />} />
</Route>
I have been through this. I think you should install React Router first (Already installed it seems)
npm install react-router-dom#6
I suggest using it in the following way -
function App() {
return (
<Router>
<div className='container'>
<div className='Header'>
<h2>Blog Site</h2>
</div>
<div className='links'> // Mention your links here
<ul>
<li>
<Link to="/tag">Tags</Link>
</li>
<li>
<Link to="/startup">Startups</Link>
</li>
</ul>
</div>
<Routes> // Describe your routes here
<Route exact path="/tag" element={<Tag />} />
<Route exact path="/startup" element={<Startup />} />
</Routes>
</div>
</Router>
);
}
I have picked small code piece from my project, you can try using my approach.
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
I am trying to set up a login page for my app, but when I try to redirect using this.props.history.push the new page does not render. My app uses redux which wraps my main file AsyncApp with Provider. AsyncApp has all my routes wrapped with various navigation bars that appear on every page. Now I am trying to do a login page but I don't know how to implement its route in my application since its route does not use the navigation bars therefore it will not reside in AsyncApp. I dont want to rename all my existing pages because the login page is the only page that does use the navigation bars.
I have tried making a component APP that is wrapped my the provider and has a route for the login page and the other routes. This isn't working.
Root.js
const store = configureStore()
export default class Root extends Component {
render() {
return (
<Provider store={store}>
<App />
</Provider>
)
}
}
App.js
export default class App extends Component {
render() {
let arr = window.location.pathname.split('/');
let loc = arr[1];
if(loc === 'signin'){
return (
<Router>
<Route exact path="/signin" component={SignIn} />
</Router>
)
} else {
return (
<AsyncApp />
)
}
}
}
AsyncApp.js
class AsyncApp extends Component {
render() {
const { classes } = this.props
return (
<ThemeProvider theme={theme}>
<div className={classes.root}>
<CssBaseline />
<nav className={classes.drawer}>
<Hidden xsDown implementation="css">
<Navigator PaperProps={{ style: { width: drawerWidth } }} />
</Hidden>
</nav>
<div className={classes.appContent}>
<Header onDrawerToggle={this.handleDrawerToggle} />
<main className={classes.mainContent}>
<div>
<Router>
<Route exact path="/EditContracts/:contractId/sections/:section" component={EditSection} />
<Route exact path="/EditContracts/:contractId" component={EditContract} />
<Route exact path="/EditUsers/:userId" component={EditUser} />
<Route exact path="/EditEndpoints/:epId" component={EditEndpoint} />
<Route exact path="/EditContracts/:contractId/addSection" component={CreateSection} />
<Route exact path="/Contracts/List" component={Contracts} />
<Route exact path="/Contracts/Create" component={CreateContract} />
<Route exact path="/Contracts/Import" component={ImportContract} />
<Route exact path="/Users/List" component={Users} />
<Route exact path="/Users/Create" component={CreateUser} />
<Route exact path="/Endpoints/Create" component={CreateEndpoint} />
<Route exact path="/Endpoints/List" component={Endpoints} />
</Router>
</div>
</main>
</div>
</div>
</ThemeProvider>
)
}
}
I expect to be able to keep AsyncApp how it is while being able to have a login page that can redirect to any page on AsyncApp.
1) Wrap the entire app around a router so you don't have to have multiple routers set up:
export default class Root extends Component {
render() {
return (
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
)
}
}
2) Utilize the Switch function to route your pages
export default class App extends Component {
render() {
<Switch>
<Route exact path="/signin" component={SignIn} />
<Route path="/" component={AsyncApp} />
</Switch>
}
}
class AsyncApp extends Component {
...
<Switch>
<Route exact path="/EditContracts/:contractId/sections/:section" component={EditSection} />
<Route exact path="/EditContracts/:contractId" component={EditContract} />
<Route exact path="/EditUsers/:userId" component={EditUser} />
<Route exact path="/EditEndpoints/:epId" component={EditEndpoint} />
<Route exact path="/EditContracts/:contractId/addSection" component={CreateSection} />
<Route exact path="/Contracts/List" component={Contracts} />
<Route exact path="/Contracts/Create" component={CreateContract} />
<Route exact path="/Contracts/Import" component={ImportContract} />
<Route exact path="/Users/List" component={Users} />
<Route exact path="/Users/Create" component={CreateUser} />
<Route exact path="/Endpoints/Create" component={CreateEndpoint} />
<Route exact path="/Endpoints/List" component={Endpoints} />
</Switch>
...
3) In your SignIn component add a state variable called redirect that you set to true if you are signed in. Then
if (redirect) {
return <Redirect to="path/to/redirect" />
}
This will set up your routes and allow you to do your redirects w/out manipulating the window and refreshing the app
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
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={ }