React router v6, group routes by feature - javascript

I am using React router v6.
THE PROBLEM:
my App.tsx is very big as it includes routes for all of the application:
Ex.
...
<Route path="products/" element={<ProductsList />} />
<Route path="products/:slug" element={<ProductView />} />
... about 300 lines
I would like to group these routes by feature so that I end up having something like this:
...
<Route path="admin" element={<AdminRoutes />} />
<Route path="products" element={<ProductsRoute />} />
...
it would look cleaner and easier to read.
So far I have created something like this for the Admin section:
export const AdminRoutes = (): any => {
return (
<Routes>
<Route path="admin" element={<Admin />}>
</Routes>
)}
and I have imported it like this inside App.tsx:
...
<Route element={<AdminRoutes />} path="admin" />
...
I am expecting to see the <Admin /> component (defined in AdminRoutes), although I don't get any errors the screen is blank.

export const AdminRoutes = (): any => {
return (
<Routes>
<Route path="admin" element={<Admin />}>
</Routes>
)}
Since you're using relative paths, the actual url that this will match is /admin/admin, one comes from the top level route in App, and another from here. Assuming you wanted this to only match "/admin", you can instead do:
<Route path="*" element={<Admin />}/> // Matches /admin
<Route path="dashboard" element={<Dashboard/>}/> // Matches /admin/dashboard
Or you could use an absolute path:
<Route path="/admin" element={<Admin />}/>
<Route path="/admin/dashboard" element={<Dashboard/>}

Related

How to add ```Context``` with routes set up?

I want to add the searchContext context in my App.js so that my Navbar an Results components have access to the variables in it. How would I do this with my routes set up? I tried to just add with with them but that didn't work. This is the code.
<Router>
// Where does <searchContext.Provider> go?
<Navbar></Navbar>
<Routes>
<Route exact path='/' element={<Home />} />
<Route path='/results'>
<Route path='/results/:value' element={<Results />} />
{/*<Route path='/results/:value/:slot' element={<Slot />}*/}
</Route>
// Another route that has nothing to do with searchContext
</Routes>
</Router>
Edit: Added "// Another route that has nothing to do with searchContext"
if i were you i would just wrap the all thing with the provider as long as its not to heavy.
Hellow, this goes with general understanding of context Api,
now the structure of your folders is your choice but i'll be very brief here
//on your context file searchContext.js
import {useState,createContext} from 'react';
export const SearchContext = createContext(null);
export const ContextProvider = props => {
const [search,setSearch] = useState(null);
return <SearchContext.Provider value = {{search,setSearch}}>
{children>
</SearchContext.Provider>
}
//now on your route.js
import { ContextProvider} from '../your/path/file';
....
<Router>
// Where does <searchContext.Provider> go?
<ContextProvider>
<Navbar></Navbar>
<Routes>
<Route exact path='/' element={<Home />} />
<Route path='/results'>
<Route path='/results/:value' element={<Results />} />
{/*<Route path='/results/:value/:slot' element={<Slot />}*/}
</Route>
// Another route that has nothing to do with searchContext
</Routes>
</ContextProvider>
</Router>

React Router. How to check if URL: ID exists in functional component?

Component is loaded on the correct path like /characters/kabal -- (kabal it`s ID)
But its loaded if you just enter any text after /characters/ for example /characters/548fnufndf or /characters/548fnufndf/dnbsdnhdj/dfmd
How to check the correct path in a functional component before loading the component and, if the path is wrong, redirect to another page?
//App.js
<Switch>
<Route
path="/characters"
exact
component={Characters}/>
<Route
exect
path="/characters/:id"
render={(props) => <CharacterPage {...props}/>}
/>
<Route
exect
path="/settings"
component={Settings}/>}
/>
<Route exect insecure component={Error} />
</Switch>
//Link to component and array of IDs
const item = [
{charId:'fujin'},
{charId:'scorpion'},
{charId:'kabal'}
]
<Link
exact="true"
to={{
pathname:`/characters/${item.charId}`,
}}
</Link>
//A component that should be loaded only if a link with this id exists.
const Scrollable = ({match}) => {
useEffect(() => {
let id = data[match.params.id]
if(!id) {
return <Redirect to="/" />
}
}, [])
}
What version of React-router are you using?
Here's a similar question: React-Router: No Not Found Route?
In summary
If you're using v4 or v5 then:
Keep the path (url stays unchanged)
<Switch>
<Route exact path="/users" component={MyComponent} />
<Route component={GenericNotFound} />
</Switch>
Redirect to another route (change url)
<Switch>
<Route path="/users" component={MyComponent} />
<Route path="/404" component={GenericNotFound} />
<Redirect to="/404" />
</Switch>
Pay attention to the order as well, NotFoundComponent must be last for that path. Also like what #cbr said, exect should be exact.

React Router Redux always show first route

React router redux always show the first route. No matter which url i entered, it will render the first route.
Index.js file
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
App.js file
export default function App() {
return (
<Switch>
<Route to="/" component={Dashboard} key={1} />;
<Route to="/icons" component={Icons} key={2} />;
</Switch>
);
}
just add exact={true} to Route, default exact is set to false, just take a look here.
<Route exact path="/" component={Dashboard} key={1} />;
When you make use Switch, you need to add the Routes, whose paths are prefixes to other Routes at the end since Switch matches and renders the first route that matched.
export default function App() {
return (
<Switch>
<Route to="/icons" component={Icons} key={2} />
<Route to="/" component={Dashboard} key={1} />
</Switch>
);
}
And you don't need ; at the end of JSX statements
This is because of the bad route configuration in your example. You need to add exact prop to the first route.
Example:
<Switch>
<Route exact to="/" component={Dashboard} />;
<Route to="/icons" component={Icons} />;
</Switch>
If you don't add exact to the "/" route, then it will always be matched, because every other route also has the / as its part.
My suggestion is to define all routes as exact by default, and only set non-exact routes when required such as:
<Switch>
<Route exact to="/" component={Dashboard} key={1} />;
<Route exact to="/icons" component={Icons} key={2} />;
<Route to="/icons/:iconId" component={IconDetails} key={3} />;
</Switch>

Loop through an array to create routes in react router

I want to hit an API which returns me all the routes of the website that I will need for the react website.
I'm not entirely sure on how to do it or even google an example.
My code looks like this:
ReactDOM.render(
<Router history={browserHistory}>
<Route path="/" component={App}>
<IndexRoute pageId={5} background="" component={Home}/>
<Route path="/your-journey" background="" pageId={7} component={YourJourney}/>
<Route path="/designed-for-you" background="" pageId={6} component={DesignedForYou}/>
<Route path="/join-us" background="" pageId={1} component={JoinUs}/>
<Route path="/get-in-touch" background="no-hero-image" pageId={4} component={GetInTouch}/>
<Route path="/legal-and-compliance" background="no-hero-image" pageId={8} component={Legal}/>
<Route path="/privacy" background="no-hero-image" pageId={9} component={Privacy}/>
</Route>
</Router>,
document.getElementById('root')
);
Where everything under the Route path="/" needs to come from the API.
Simple, just load the data in some action that loads your routes and map over the result in your ReactDOM.render function. It'll look something like this:
// This just maps the component string names (keys) to actual react components (values)
const COMPONENT_MAP = {
'Privacy': Privacy, // quotes are not necessary, just illustrating the difference a bit more
// ... other mappings
}
// Some asynch action that loads the routes from your API
getRoutes().then((routes) => {
ReactDOM.render(
<Router history={browserHistory}>
<Route path="/" component={App}>
<IndexRoute pageId={5} background="" component={Home}/>
{routes.map((r) => {
return <Route path={r.path} background={r.bg} pageId={r.pageId} component={COMPONENT_MAP[r.component]}/>
}}
</Route>
</Router>,
document.getElementById('root')
);
});

Creating react-router Routes in a function

Is it possible to create the <Route> elements through a function? I would like to display different routes/pages and the application is not aware how many they are. The pages are in the state stored in an array of page objects. Each page object have an id, title, path and body elements (so far). I think that my Router should look like this:
render((
<Router history={browserHistory}>
<Route path="/" component={App}>
<Route path="page1" component={CommonPage}/>
<Route path="page2" component={CommonPage} />
<Route path="page3" component={CommonPage} />
<Route path="page4" component={CommonPage}/>
<Route path="page5" component={CommonPage} />
<Route path="page6" component={CommonPage} />
</Route>
<Route path="*" component={NoMatch}/>
</Route>
</Router>
), document.body)
And I would like to define it with a function like:
render((
<Router history={browserHistory}>
<Route path="/" component={App}>
{
mapPagesToRoutes(pages)
}
<Route path="*" component={NoMatch}/>
</Route>
</Router>
), document.body)
mapPagesToRoutes(pages) {
return pages.map( page => () {
if(page.type === 'CommonPage' {
return <Route path={page.path} component={CommonPage}
}
}
}
Q1: How is this done?
Q2: How do I identify each with something other than the path. Can I use some sort of key=page.id in <Route>?
If you want to pass properties to your child route components, you can do something like this:
<Route path={page.path} component={() => <CommonPage someProp={page.someProp}/>}/>
If you want to dynamically create React Routes then you can use a route with a parameter, like so. Here's your Router:
render((
<Router history={browserHistory}>
<Route path="/" component={App}>
<Route path="/page:pageNumber" pages={this.state.pages} component={CommonPage} />
<Route path="*" component={NoMatch}/>
</Route>
</Router>
), document.body)
Then in your CommonPage component have something like this:
render() {
return(<div>This is {this.props.params.pageNumber}</div>);
}
That should give you the ability to navigate to any /pageX route. Then in CommonPage component you can compare the pageNumber parameter and the pages property (available via this.props.route.pages) to see if the current page number is valid

Categories