Warning: You should not use Route component and Route children in the same route; Route component will be ignored
import { BrowserRouter, Route, Switch } from "react-router-dom"
import { useState } from "react";
import SideBar from "./SideBar";
import Playing from "./Playing";
import "./App.css";
import AllSong from "./Components/AllSong";
import Favourites from "./Components/Favourites";
function App() {
const [sidebar, setSidebar] = useState(false);
return (
<BrowserRouter>
<div className="box image photo">
<SideBar sidebar={sidebar}/>
<Switch>
<Route path="/" exact component={Playing}>
<Playing sidebar={sidebar} setSidebar={(bool) => setSidebar(bool)}/>
</Route>
<Route path="/AllSong" component={AllSong}/>
<Route path="/Favourites" component={Favourites}/>
</Switch>
</div>
</BrowserRouter>
);
}
export default App;
Can someone explain why is the warning coming and also help to improve the code. (I'm new to react)
I tried using the v6 for react-router and react-router-dom b ut it showed number of errors so i degraded again and used switch again
Thanks You.
This is happening because you have <Route path="/" ...> & within that you have <Playing... so this confuses the Router & it doesn't know whether to render the parent <Route ... or the child <Playing... hence the error.
Like the warning says, you can't specify both a route component and wrap children components.
From the docs:
Warning: <Route children> takes precedence over both <Route component> and <Route render> so don’t use more than one in the
same <Route>.
The issue is specifically with:
<Route path="/" exact component={Playing}>
<Playing sidebar={sidebar} setSidebar={(bool) => setSidebar(bool)}/>
</Route>
You are rendering Playing in both places. Since it seems like you want to pass additional props into Playing then I suggest using the render prop so Playing can also still receive route props, i.e. history, location, and match props.
<Route
path="/"
exact
render={props => (
<Playing
{...props}
sidebar={sidebar}
setSidebar={(bool) => setSidebar(bool)}
/>
)}
/>
See Route render methods for further clarification on rendering routed content by a Route component.
it is specifically these lines:
<Route path="/" exact component={Playing}>
<Playing sidebar={sidebar} setSidebar={(bool) => setSidebar(bool)}/>
</Route>
you're setting both the component
component={Playing}
and the children
<Playing sidebar={sidebar} setSidebar={(bool) => setSidebar(bool)}/>
React will only render one of them so one of them has to be ignored, in this case the component.
If you remove one of them the warning will disappear.
Related
I currently have all the Routes in my app defined in App.js. Would like to be able to pass state (as props) from the Alignment component down to the GPfSOA component.
function App() {
return (
<Router>
<div className="App">
<Nav />
<Switch>
<Route path="/" exact component={Home} />
<Route path="/about" exact component={About} />
<Route path="/alignments" exact component={Alignments} />
<Route path="/alignments/:id" exact component={Alignment} />
<Route path="/alignments/segmentinfo/:id" exact component={Segments} />
<Route path="/alignments/segmentinfo/:id/:segid" exact component={Segment} />
<Route path="/alignments/getpoint/:id" exact component={GPfSOA} />
<Route path="/alignments/getstatoff/:id" exact component={GSOfPA} />
<Route path="/alignments/getalsfromxy/:x/:y" exact component={AlignList} />
<Route path="/alignments/getsegsfromxy/:x/:y" exact component={SegmentList} />
<Route path="/alignments/post/create" exact component={AddAlignment} />
<Route path="/alignments/put/update/:id" exact component={EditAlignment} />
<Route path="/alignments/ptso/list" exact component={TogglePoints} />
<Route path="/alignments/ptso/list/:ptid" exact component={Point} />
<Route path="/" render={() => <div>404</div>} />
</Switch>
</div>
</Router>
);
}
The order from parent on down to the greatest grandchild would be App > Alignments > Alignment > GPfSOA. Trying to pass item.alignment (the alignment's name) from the Alignment component down (or over) to the GPfSOA component so that it can be rendered there. item.alignment is a property of the Alignmnet component's state.
Do I need to set these up as nested routes in order to accomplish this (a.k.a. cut and paste all the Routes from App.js that are children of the Alignment component and paste them into the Alignment component)?
Having a hard time understanding how to define a particular component as being a parent and another component as being a child of that component. All the examples I see assume you want to pass props from App.js down to some other component. Looking for examples with React Hooks and React Router in play (functions rather than classes) where you're passing props from a component 'below' App.js down to another component that's further down in the hierarchy. Hope this makes sense.
Found lots of examples such as this one for 'passing function as a render props in Route component' (supposedly the recommended way to do this)
const PropsPage = () => {
return (
<h3>Props Page</h3>
);
};
const App = () => {
return (
<section className="App">
<Router>
...
<Link to="/404-not-found">404</Link>
<Link to="/props-through-render">Props through render</Link>
<Switch>
...
<Route exact path="/props-through-render" render={(props) => <PropsPage {...props} title={`Props through render`} />} />
<Route component={NoMatchPage} />
</Switch>
</Router>
about with browser reload
</section>
);
};
export default App;
But like I stated before, this example and every other one I've found assume you want to pass props from App.js down to another component.
Your issue can be handle with creating Alignment context
import React, { createContext, useState } from "react";
const AlignmentContext = createContext();
const AlignmentContextProvider = ({ children }) => {
const [num, setNum] = useState(1);
};
return (
<AlignmentContext.Provider value={{ num, setNum }}>
{children}
</AlignmentContext.Provider>
);
};
export { AlignmentContext, AlignmentContextProvider };
now wrap your routes needed to be in same context with AlignmentContextProvider
import { AlignmentContextProvider } from 'pathto/context'
<AlignmentContextProvider>
<Route path="/alignments/:id" exact component={Alignment} />
<Route path="/alignments/segmentinfo/:id" exact component={Segments} />
<Route path="/alignments/segmentinfo/:id/:segid" exact component={Segment} />
<Route path="/alignments/getpoint/:id" exact component={GPfSOA} />
</AlignmentContextProvider>
and use useContext hooks for reach values
import React, { useContext } from "react";
import { AlignmentContext } from 'pathto/context';
const GPfSOA = () => {
const { num, setNum } = useContext(AlignmentContext);
Please read this properly before marking as duplicate, I assure you I've read and tried everything everyone suggests about this issue on stackoverflow and github.
I have a route within my app rendered as below;
<div>
<Header compact={this.state.compact} impersonateUser={this.impersonateUser} users={users} organisations={this.props.organisations} user={user} logOut={this.logout} />
<div className="container">
{user && <Route path="/" component={() => <Routes userRole={user.Role} />} />}
</div>
{this.props.alerts.map((alert) =>
<AlertContainer key={alert.Id} error={alert.Error} messageTitle={alert.Error ? alert.Message : "Alert"} messageBody={alert.Error ? undefined : alert.Message} />)
}
</div>
The route rendering Routes renders a component that switches on the user role and lazy loads the correct routes component based on that role, that routes component renders a switch for the main pages. Simplified this looks like the below.
import * as React from 'react';
import LoadingPage from '../../components/sharedPages/loadingPage/LoadingPage';
import * as Loadable from 'react-loadable';
export interface RoutesProps {
userRole: string;
}
const Routes = ({ userRole }) => {
var RoleRoutesComponent: any = null;
switch (userRole) {
case "Admin":
RoleRoutesComponent = Loadable({
loader: () => import('./systemAdminRoutes/SystemAdminRoutes'),
loading: () => <LoadingPage />
});
break;
default:
break;
}
return (
<div>
<RoleRoutesComponent/>
</div>
);
}
export default Routes;
And then the routes component
const SystemAdminRoutes = () => {
var key = "/";
return (
<Switch>
<Route key={key} exact path="/" component={HomePage} />
<Route key={key} exact path="/home" component={HomePage} />
<Route key={key} path="/second" component={SecondPage} />
<Route key={key} path="/third" component={ThirdPage} />
...
<Route key={key} component={NotFoundPage} />
</Switch>
);
}
export default SystemAdminRoutes;
So the issue is whenever the user navigates from "/" to "/second" etc... app re-renders Routes, meaning the role switch logic is rerun, the user-specific routes are reloaded and re-rendered and state on pages is lost.
Things I've tried;
I've tried this with both react-loadable and React.lazy() and it has the same issue.
I've tried making the routes components classes
Giving all Routes down the tree the same key
Rendering all components down to the switch with path "/" but still the same problem.
Changing Route's component prop to render.
Changing the main app render method to component={Routes} and getting props via redux
There must be something wrong with the way I'm rendering the main routes component in the app component but I'm stumped, can anyone shed some light? Also note this has nothing to do with react-router's switch.
EDIT: I've modified one of my old test project to demonstrate this bug, you can clone the repo from https://github.com/Trackerchum/route-bug-demo - once the repo's cloned just run an npm install in root dir and npm start. I've got it logging to console when the Routes and SystemAdminRoutes are re-rendered/remounted
EDIT: I've opened an issue about this on GitHub, possible bug
Route re-rendering component on every path change, despite path of "/"
Found the reason this is happening straight from a developer (credit Tim Dorr). The route is re-rendering the component every time because it is an anonymous function. This happens twice down the tree, both in App and Routes (within Loadable function), below respectively.
<Route path="/" component={() => <Routes userRole={user.Role} />} />
needs to be
<Routes userRole={user.Role} />
and
loader: () => import('./systemAdminRoutes/SystemAdminRoutes')
Basically my whole approach needs to be rethought
EDIT: I eventually fixed this by using the render method on route:
<Route path="/" render={() => <Routes userRole={user.Role} />} />
Bumped into this problem and solved it like this:
In the component:
import {useParams} from "react-router-dom";
const {userRole: roleFromRoute} = useParams();
const [userRole, setUserRole] = useState(null);
useEffect(()=>{
setUserRole(roleFromRoute);
},[roleFromRoute]}
In the routes:
<Route path="/generic/:userRole" component={myComponent} />
This sets up a generic route with a parameter for the role.
In the component useParams picks up the changed parameter und the useEffect sets a state to trigger the render and whatever busines logic is needed.
},[userRole]);
Just put the "/" in the end and put the other routes above it.
Basically it's matching the first available option, so it matches "/" every time.
<Switch>
<Route key={key} exact path="/home" component={HomePage} />
<Route key={key} path="/second" component={SecondPage} />
<Route key={key} path="/third" component={ThirdPage} />
<Route key={key} exact path="/" component={HomePage} />
<Route key={key} component={NotFoundPage} />
</Switch>
OR
<Switch>
<Route path="/second" component={SecondPage} />
<Route exact path="/" component={HomePage} />
<Route path="*" component={NotFound} />
</Switch>
Reorder like this, it will start working.
Simple :)
import React from 'react';
import SearchDocument from './components/searchDocument';
import CreateRequest from './components/createRequest';
import { BrowserRouter as Router } from "react-router-dom";
import { Route, Switch } from 'react-router-dom';
class App extends React.Component {
render() {
return (
<Router>
<div>
<Switch>
<Route exact path='/' component={Home} />
<Route path='/home' component={Home} />
<Route path='/create' component={CreateRequest} />
<Route path='/searchDocument' component{SearchDocument} />
<Route path='/upload' component={UploadDocument} />
<Route path='/search' component={Search} />
</Switch>
</div>
</Router>
);
}
}
export default App;
I am new to react router.I want to pass props through route to create request component.I tried different methods to pass props but that doesn't work.Can anyone please suggest, how to send props to component and how to handle them in that component.Above is my code.Thanks in advance
As mentioned in the comments, you can use the render prop instead of the component.
From the docs:
Instead of having a new React element created for you using the component prop, you can pass in a function to be called when the location matches. The render prop receives all the same route props as the component render prop.
And an example with your code will look like this:
<Route path='/searchDocument' render={(props) => <SearchDocument yourNewProp={yourNewProp} {...props} />} />
I am attempting to render a component when I enter a url that does not exists. However, the component keeps rendering in all routes. I am using react-router-dom#4.1.1. This are the routes that I set up:
import * as React from "react";
import { Route, RouteComponentProps } from "react-router-dom";
import glamorous from "glamorous";
import ElementList from "./elementlist";
import AddElement from "./addelement";
import NotFound from "./NotFound";
const Styling = glamorous.div({
minHeight: 5,
minWidth: 8
});
const NavRouter = () => (
<Styling>
<Route path="/" exact={true} component={ElementList} />
<Route path="/addelement" component={(props:
RouteComponentProps<{}>) => (
<AddElement onSubmitSuccess={() => props.history.push("/")} />
)} />
<Route path="*" exact={true} component={NotFound}/>
</Styling>
);
export default NavRouter;
This is my NotFound component:
import * as React from "react";
const NotFound = () => (
<h1>The page that you are looking is not there.</h1>
);
export default NotFound;
The issue that I am currently facing is that the message: The page that you are looking is not there. keeps popping up on the / and /addelement route when I changed the URL. I am having a hard time trying to make the message appear only when I go to a route that is not defined. Initially, I tried to switch the routes and make the more "detailed" route at the top like this:
const NavRouter = () => (
<Styling>
<Route path="/addelement" component={(props:
RouteComponentProps<{}>) => (
<AddElement onSubmitSuccess={() => props.history.push("/")} />
)} />
<Route path="/" exact={true} component={ElementList} />
<Route path="*" component={NotFound}/>
</Styling>
);
However, it did not solve the issue. Is there a way to prevent the message from appearing on every route that I go to except for routes that are not defined?
You should use a <Switch> component. Per the documentation:
How is this different than just using a bunch of <Route>s?
<Switch> is unique in that it renders a route exclusively. In contrast, every <Route> that matches the location renders inclusively. Consider this code:
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
If the URL is /about, then <About>, <User>, and <NoMatch> will all render because they all match the path. This is by design, allowing us to compose <Route>s into our apps in many ways, like sidebars and breadcrumbs, bootstrap tabs, etc.
Occasionally, however, we want to pick only one <Route> to render. If we’re at /about we don’t want to also match /:user (or show our “404” page).
Thus, import it from react-router-dom:
import { Route, RouteComponentProps, Switch } from 'react-router-dom';
Then apply it like so (note there is no need for path="*"):
<Switch>
<Route path="/" exact={true} component={ElementList} />
<Route path="/addelement" component={(props:
RouteComponentProps<{}>) => (
<AddElement onSubmitSuccess={() => props.history.push("/")} />
)} />
<Route component={NotFound}/>
</Switch>
I am attempting to render a component when I enter a url that does not exists. However, the component keeps rendering in all routes. I am using react-router-dom#4.1.1. This are the routes that I set up:
import * as React from "react";
import { Route, RouteComponentProps } from "react-router-dom";
import glamorous from "glamorous";
import ElementList from "./elementlist";
import AddElement from "./addelement";
import NotFound from "./NotFound";
const Styling = glamorous.div({
minHeight: 5,
minWidth: 8
});
const NavRouter = () => (
<Styling>
<Route path="/" exact={true} component={ElementList} />
<Route path="/addelement" component={(props:
RouteComponentProps<{}>) => (
<AddElement onSubmitSuccess={() => props.history.push("/")} />
)} />
<Route path="*" exact={true} component={NotFound}/>
</Styling>
);
export default NavRouter;
This is my NotFound component:
import * as React from "react";
const NotFound = () => (
<h1>The page that you are looking is not there.</h1>
);
export default NotFound;
The issue that I am currently facing is that the message: The page that you are looking is not there. keeps popping up on the / and /addelement route when I changed the URL. I am having a hard time trying to make the message appear only when I go to a route that is not defined. Initially, I tried to switch the routes and make the more "detailed" route at the top like this:
const NavRouter = () => (
<Styling>
<Route path="/addelement" component={(props:
RouteComponentProps<{}>) => (
<AddElement onSubmitSuccess={() => props.history.push("/")} />
)} />
<Route path="/" exact={true} component={ElementList} />
<Route path="*" component={NotFound}/>
</Styling>
);
However, it did not solve the issue. Is there a way to prevent the message from appearing on every route that I go to except for routes that are not defined?
You should use a <Switch> component. Per the documentation:
How is this different than just using a bunch of <Route>s?
<Switch> is unique in that it renders a route exclusively. In contrast, every <Route> that matches the location renders inclusively. Consider this code:
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
If the URL is /about, then <About>, <User>, and <NoMatch> will all render because they all match the path. This is by design, allowing us to compose <Route>s into our apps in many ways, like sidebars and breadcrumbs, bootstrap tabs, etc.
Occasionally, however, we want to pick only one <Route> to render. If we’re at /about we don’t want to also match /:user (or show our “404” page).
Thus, import it from react-router-dom:
import { Route, RouteComponentProps, Switch } from 'react-router-dom';
Then apply it like so (note there is no need for path="*"):
<Switch>
<Route path="/" exact={true} component={ElementList} />
<Route path="/addelement" component={(props:
RouteComponentProps<{}>) => (
<AddElement onSubmitSuccess={() => props.history.push("/")} />
)} />
<Route component={NotFound}/>
</Switch>