I have been assigned a task where I must put a route with the following url: /items?search= to load SearchBarScreen component.
I have this code and I am using react-router-dom package:
export const AppRouter = () => {
return (
<Router>
<Switch>
<Route exact path="/items?search=" component={SearchBarScreen} />
<Route exact path="/product/:id" component={ProductDetailScreen} />
<Route path="/" component={HomeScreen} />
<Route component={NotFoundScreen} />
</Switch>
</Router>
);
I can't load my SearchBarScreen component with the url:
http://localhost:3000/items?search=XDDD
the route HomeScreen (/) is loaded in this case :(
what am I doing wrong?
You should feed the URI without the query string to the Route component. So if you want to render your SearchBarScreen at this URL http://localhost:3000/items?search=, you should do this:
<Route exact path="/items" component={SearchBarScreen} />
And then access the query string inside SearchBarScreen like so:
const SearchBarScreen = ({ match, location }) => {
console.log(location.search);
return <div>Search results</div>;
};
Another way is to drop the exact prop.
My recommended solution is the former. Here is a Sandbox: https://codesandbox.io/s/elated-http-lkqfj?file=/src/App.js
The exact param is used when you have multiple paths that have similar names:
for exmplae in your code when you go to //localhost:3000/items?search=XDDD the router will go through all of our defined routes and return the FIRST match it finds.And this is the first thing it finds //localhost:3000/ And executes the HomeScreen component.
The exact param disables the partial matching for a route and makes sure that it only returns the route if the path is an EXACT match to the current url.
So in this case,you should add exact to / route:
<Router>
<Switch>
<Route path="/items?search=" component={SearchBarScreen} />
<Route path="/product/:id" component={ProductDetailScreen} />
<Route exact path="/" component={HomeScreen} />
<Route component={NotFoundScreen} />
</Switch>
</Router>
You can do something like this
You can use this custom hook
useLocation hook is imported from react-router-dom
useQuery() {
return new URLSearchParams(useLocation().search);
}
Then in component
const query = useQuery();
Docs Query param example
Related
I required to redirect from parent path to child path as a default. but the route is getting updates. but the component is not rendering.
here is my route details:
Lazy part:
const UK = React.lazy(() => import("./components/page-projects/project-uk/project-uk.component"));
const FR = React.lazy(() => import("./components/page-projects/project-france/project-france.component"));
const LT = React.lazy(() => import("./components/page-projects/project-lithuania/project-lithuania.component"));
Route path:
<Redirect from="/projects" to="/projects/united-kingdom">
<Route path="/projects/united-kingdom" component={UK}></Route>
<Route path="/projects/france" component={FR}></Route>
<Route path="/projects/lithuania" component={LT}></Route>
</Redirect>
what is wrong here? any one help me? my version of react is 17x
The other routes don't have to be children of Redirect.
You should be doing something like this
<Switch>
<Redirect from="/projects" to="/projects/united-kingdom" />
<Route path="/projects/united-kingdom" component={UK} />
<Route path="/projects/france" component={FR} />
<Route path="/projects/lithuania" component={LT} />
</Switch>
Reference https://reactrouter.com/web/api/Redirect
The <Switch /> component will only render the first route that matches the path. Once it finds the first route that matches the path, it will not look for any other matches. Not only that, it allows for nested routes to work properly and since the Redirect is a route you should wrap under the Switch component
<Switch>
<Redirect from="/projects" to="/projects/united-kingdom" />
<Route path="/projects/united-kingdom" component={UK} />
<Route path="/projects/france" component={FR} />
<Route path="/projects/lithuania" component={LT} />
</Switch>
I have many routes
<Route exact path="/" component={Test} />
<Route exact path="/1" component={Test1} />
<Route exact path="/2" component={Test2} />
In every component i use useLocation to get the data from route. It exists a possibility to pass in Route a parameter and to access that parameter with useLocation, in every component?
Here is the example:
<Route exact path="/" parameter='this is route nr 1' component={Test} />
<Route exact path="2/" parameter='this is route nr 2' component={Test2} />
Which is the solution to do what i want to achieve?
For query params you don't need to do anything extra in <Route />. You just need to get those query params in component and parse it
To access param1 from url
/?param1=hello
import { useLocation } from 'react-router-dom';
const Test = () => {
const queryParams = new URLSearchParams(useLocation().search);
return (
<div>Test {queryParams.get('param1')}</div>
);
}
And if you want path params like
/1 // 1 from this route
In routes and you don't need to create multiple routes just to get 1,2 etc
<Route exact path="/:id" component={Test} />
In component
import { useParams } from 'react-router-dom';
const Test = () => {
let { id } = useParams();
return (
<div>Test ID: {id}</div>
);
}
It seems from your question that you search for a way to pass data to routes only at the router declaration. therefore you can use regular props instead of location data extract -
<Route exact path="/" render={()=><Test parameter={'this is route nr 1'} />} />
You can either pass props to the component directly using render:
<Route
exact
path="/"
render={props => <MyComponent {...props} foo="hello world" bar={false} /> }
/>
or you can use query params:
<Route
exact
path={`/user?id=${user_id}`}
component={MyComponent}
/>
and then in MyComponent you can access props.match.params.id
React-router docs are a great start
I am trying to set the following to different numbers based on the page the user is on using window.location.path
const [value, setValue] = React.useState(1);
I have tried if statement and I seem to get errors so my thinking was to set a params to
<Route exact path="/" component={Home} />
however while I understand I could do something like
<Route exact path="/:id" component={Home} />
the issue is the following as you can see below I have a number of set paths, the tabs in the nav bar are linked to the main path (/, /about, /news, /programs etc)
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about/" component={About} />
<Route path="/news/:id" component={News} />
<Route path="/programs/:id" component={Programs} />
<Route path="/podcast/:id" component={Podcast} />
</Switch>
I want to be able to send a number with each Route so that way I can just set the following with something like
const [value, setValue] = React.useState({pageID});
I was thinking something like
<Route path="/podcast/:id" pageID="4" component={Podcast} />
How can I do this?
let say that you are using this in component News
The first step to be able to extract the param out of the link is using withRouter
Import it in your component News file: import { withRouter } from "react-router";
We need to wrap the component inside the withRouter HOC as follows:
//instead of exporting it as export default News.
export default withRouter(News) //this will make the API we need available at the component's props
supposing you want to do that:
const [value, setValue] = React.useState({pageID});
at the component mount, inside componentDidMount we can extract the param as follows:
const { id } = this.props.match.params //the id the user navigated to: /news/:id
and then you can use the id to update your state.
You can try to pass parameters to component with render method.
<Switch>
<Route exact path="/" render={(props) => <Home pageId=1 {...props} />} />
<Route path="/about/" render={(props) => <About pageId=2 {...props} />} />
</Switch>
You can add multiple params to the path as -
path="/podcast/:id/:pageId"
And to retrieve -
this.props.match.params.pageId
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 :)
I am using React Router v4 for routing in my application. The only issue I have is the query params are ignored while navigation from one route to another. Is there a way to just replace the path and preserve the query params.
Below is my code:
<Switch>
<Route exact path="/" component={() => <Redirect to="/Route1" />}/>
<Route exact path='/Route1' component={Route1Comp} />
<Route path='/Route1/:channel/:id?'
render={(routeProps) => (
<AppMain {...routeProps} />
)}
/>
<Route exact path='/Route2' component={Route2Comp} />
</Switch>
I need the app to have a query param ?isDev=true and want to retain across. Currently if I am on localhost:3000/Route1Comp?isDev=true and navigate to Route2Comp using Link then the entire path is replaced along with query params.
You can extend the Link component from react-router to include the search params by default like
const ExtendedLink = ({ to, children, location}) => {
return <Link to={{
pathname: to,
search: location.search
}}>{children}</Link>
}
export default withRouter(ExtendedLink)
and then use it instead of Link
<ExtendedLink to='/Route1'>Route 1</ExtendedLink>