How to encode react route params in path? - javascript

I am working on a reactJs project and reading the code and facing one issue.
Following is the structure of routes
<Routes>
<Route index element={<List />} />
<Route path={NewRelativePath} element={<New />} />
<Route path={RouteParams.subject} element={<Details />} />
<Route path={EditRelativePath} element={<Edit />} />
<Route
path={clusterSchemaSchemaDiffRelativePath}
element={<DiffContainer />}
/>
</Routes
I have an issue in this route <Route path={RouteParams.subject} element={<Details />} />.
RouteParam subject can contain values like test/test and i want them to be transformed as test%2Ftest basically i want the subject to be encoded.
RouterParam looks like below
export enum RouteParams {
subject = ':subject',
}
I tried doing encodeURIComponent by making the change like this
<Route path={encodeURIComponent(RouteParams.subject)} element={<Details />} /> but it broke things than doing anything better.
Is there anything I can do to solve this problem ?
Many thanks in advance.

If you want to encode some sort of parameters in the route you would want to encode it inside of the component, not before hand. So something like this
<Routes>
<Route path="/subject/:subj" element={<Details/>} />
</Routes>
function Details(){
let {subj} = useParams();
const encodedSubj = encodeURIComponent(subj);
//do whatever you need to do with encodedSubj in here
}

Related

React Router V6 routed component needs state/props from another routed component

Hello I am using React router for my application. App.js code segment:
<Routes>
<Route path="/" element={<Login navigate={navigate} setOverlays={setOverlays} setToken={setToken} setUser={setUser} />} />
<Route path="/create-account" element={<CreateAccount />} />
<Route path="/projects" element={<Projects token={token} name={user.name} jobTitle={user.jobTitle} navigate={navigate} setOverlays={setOverlays} />} />
<Route path="/individual_project" element={<IndividualProject />} />
</Routes>
The last route (/individual_project) requires props that is located in the projects component. Since I do not have access to the components in App.js how can I create this route.
I also prefer not to move the state variables from the Projects component and pass them down through props.
There are few ways to achieve that:
You can move the individual_project route inside the Projects component like this:
const Projects = () => {
...other logic
return(
<Routes>
<Route path="/individual_project" element={<IndividualProject />} />
</Routes>
)
}
Docs here: https://reactrouter.com/docs/en/v6/getting-started/overview#nested-routes
Alternatively, you could also create a context to wrap the routes. Then, you can retrieve the variables directly from the context:
<Context.Provider value={yourValuesToShare}>
<Routes>
<Route path="/" element={<Login navigate={navigate} setOverlays={setOverlays} setToken={setToken} setUser={setUser} />} />
<Route path="/create-account" element={<CreateAccount />} />
<Route path="/projects" element={<Projects token={token} name={user.name} jobTitle={user.jobTitle} navigate={navigate} setOverlays={setOverlays} />} />
<Route path="/individual_project" element={<IndividualProject />} />
</Routes>
</Context.Provider>
Docs here: https://reactjs.org/docs/context.html
For this kind of scenarios , using Context API is recommended .its more precise and cleaner that the other techniques.
React docs
Context api is used to access state from any component so react context api is recommended

react routing issues when routes other that in routing config are hit

I am building a web app with different routes.
There is this case where if a user hits any arbitrary route then he gets directed to Login Component. But it only handles case where bad routing happens this way localhost:3000/gvgdvgdvgd.
I have routes such as /home/news. A user may end up hitting /home/news/10 manually which doesn't exist. Similarly there is a route such as coupon and user may end up hitting /coupons/88 without going to coupons first.
How do I handle these issues in my web-app? I handled it for the first case. Here is the routing config.
<Route path="/login" component={LoginLoadable} />
<Route path="/home" component={Home} />
<Route path="/maths" component={Maths} />
<Route
exact
path="/"
render={routeProps => (
<Component1
{...routeProps}
/>
)}
/>
<Route component={LoginLoadable}/>
What about the case where user hits maths/123/1ydhd manually when that doesn't exist?
Wrap your routes in a Switch and add a Route with no path prop that renders your 404 page. If you don't specify a path, it should always render that route. Adding a Switch makes sure only one route will render. Also you will need to add the exact prop to your routes. See:
https://reacttraining.com/react-router/web/api/Route/exact-bool for how it matches sub-routes.
Something like:
<Switch>
<Route path="/login" component={LoginLoadable} />
<Route exact path="/home" component={Home} />
<Route exact path="/maths" component={Maths} />
<Route
exact
path="/"
render={routeProps => (
<Component1
{...routeProps}
/>
)}
/>
<Route component={LoginLoadable}/> // <-- remove this since you render it in '/login'
<Route component={A404Page} // <-- add this
</Switch>

How to display different components for different users on one route?

I need to show different components in one route.
My router with authorization looks like:
<Route authorize={['admin']} component={Authorization}>
<Route path='/home' component={Home} />
</Route>
And in Authorization component I have to check if the user has a access to this route.
But the question is how to show different components on the same route?
Something like this doesn't work:
<Route authorize={['admin']} component={Authorization}>
<Route path='/home' component={AdminHome} />
</Route>
<Route authorize={['manager']} component={Authorization}>
<Route path='/home' component={MangerHome} />
</Route>
Define only one route and create a wrapper component, inside wrapper component check the condition and render different component.
Like this:
<Route authorize={['manager', 'admin']} component={Authorization}>
<Route path='/home' component={WrapperComponent} />
</Route>
Now from Authorization component pass some bool to WrapperComponent to decide between which component do you want to render.
Inside WrapperComponent:
render(){
if(this.props.isAdmin)
return <Home />
return < MangerHome />
}

How can I avoid a route collision?

I want to render a <Product> when the user visits /Products/1.
I want to render a <CreateProduct> when the user visits /Products/new.
My router looks like so:
<Route exact path="/Products/new" component={CreateProduct} />
<Route exact path="/Products/:productId" component={Product} />
If the user browses to /Products/new, it matches both routes and results in the Product component throwing errors re: not finding a product with the id new.
I haven't been able to find anything in the react-router documentation to avoid this. I could potentially use this hack, but there has to be a "better" way:
<Route exact path="/Products/new" component={CreateProduct} />
<Route exact path="/Products/:productId" render={renderProduct} />
using a function to render the <Product> route:
const renderProduct = props =>
props.match.params.productId === 'new'
? null
: <Product {...props} />;
Use <Switch />:
<Switch>
<Route exact path="/Products/new" component={CreateProduct} />
<Route exact path="/Products/:productId" component={Product} />
</Switch>
It will try to find the first match.
So /Products/new will match the first route and skip the second.
/Products/1 will match the second.

Default Route With React Router 4

fI currently have the following routes defined in my application:
/
/selectSteps
/steps
/steps/alpha
/steps/beta
/steps/charlie
Which could also be visualised like this:
- (home)
- selectSteps
- steps
- alpha
- beta
- charlie
My root component looks like this:
<Route path="/" exact component={Home} />
<Route path="/select-steps" render={() => <StepSelectorContainer />} />
<Route path="/steps" component={StepsContainer} />
My Steps component does this:
steps.map(step => (
<Route
path={fullPathForStep(step.uid)}
key={shortid.generate()}
render={() => <StepContainer step={step} />}
/>
This all works nicely, but I don't want steps to exist as route in its own right. Only its child routes should be visitable. So I'm looking to lose the /steps route to leave my routes as:
/
/selectSteps
/steps/alpha
/steps/beta
/steps/charlie
How should I configure my routes for this? Ideally, hitting /steps would redirect to the first child route.
Actually, it's pretty straightforward...
Use Redirect component to... well, redirect.
<Redirect from="/steps" exact to="/steps/whatever" />
exact prop guarantees you won't be redirected from sub-route.
Edit: after all, Redirect does support exact (or strict) props. No need to wrap in Route. Answer updated to reflect that.
Pedr,
I think that this will solve your problem.
<Route path="/" exact component={Home} />
<Route path="/select-steps" render={() => <StepSelectorContainer />} />
<Route path="/steps" component={StepsComponent} />
And then in your StepsComponent render method, you can do this.
<Switch>
{steps.map(step => (
<Route
path={fullPathForStep(step.uid)}
key={shortid.generate()}
render={() => <StepContainer step={step} />}
/>}
<Redirect from="/steps" exact to="/steps/alpha" />
</Switch>
What this will do is render your steps component because it the route begins with /steps. After that is rendered, then it will render one of the nested routes based off the url. If the url is just "/steps", then it will redirect to the initial route listed here, in this case "/steps/alpa" by rendering the redirect. The Switch will make it so that it only renders one of the routes.
Credit to Andreyco for the redirect code.
I hope this helps.

Categories

Resources