You can provide GuardProvider with multiple guards middleware for route guarding, GuardProvider can receive an array of guards and a fallback element (can be used to load loading state).
bar
} path="/bar/*">
baz
} path="/bar/baz" />
)
}">
import{BrowserRouter}from'react-router-dom'import{GuardConfigProvider,GuardedRoute,GuardedRoutes,GuardMiddleware,GuardProvider,}from'react-router-guarded-routes'constlogGuard: GuardMiddleware=(to,from,next)=>{console.log(to)// { location, matches, route }console.log(from)next()// call next function to run the next middleware or show the route element, it accepts the same parameters as navigate (useNavigate()) and behaves consistently.}// you can use object to determine whether you need to register middlewareconstbarGuard: GuardMiddleware={handler: (to,from,next)=>{console.log('bar')next()},register: (to,from)=>{// only matched with `/bar` can be executed.if(to.location.pathname.startsWith('/bar')){returntrue}returnfalse},}constguards=[logGuard,barGuard]exportdefaultfunctionApp(){return(<BrowserRouter><GuardConfigProvider>{/* Guard all routes below. */}<GuardProviderfallback={<div>loading...</div>}guards={guards}><GuardedRoutes><GuardedRouteelement={<div>foo</div>}path="/foo"/><GuardedRouteelement={<div>bar</div>}path="/bar/*"><GuardedRouteelement={<div>baz</div>}path="/bar/baz"/></GuardedRoute></GuardedRoutes></GuardProvider></GuardConfigProvider></BrowserRouter>)}
Of course, you can also set up separate fallbacks and guards for each route.
bar
}
path="/bar/*"
>
baz} path="/bar/baz" />
)
}">
import{BrowserRouter,Outlet}from'react-router-dom'import{GuardConfigProvider,GuardedRoute,GuardedRoutes,GuardMiddleware,GuardProvider,}from'react-router-guarded-routes'constlogGuard: GuardMiddleware=(to,from,next)=>{console.log(to,from)next()}constfooGuard: GuardMiddleware=(to,from,next)=>{console.log('foo')next()}constguards=[logGuard]constfooGuards=[fooGuard]exportdefaultfunctionApp(){return(<BrowserRouter><GuardConfigProvider><GuardProviderfallback={<div>loading...</div>}guards={guards}><GuardedRoutes><GuardedRoutefallback={<div>loading foo...</div>}guards={fooGuard}element={<div>foo</div>}path="/foo"/><GuardedRouteelement={<div>
bar
<Outlet/></div>}path="/bar/*"><GuardedRouteelement={<div>baz</div>}path="/bar/baz"/></GuardedRoute></GuardedRoutes></GuardProvider></GuardConfigProvider></BrowserRouter>)}
You can also call next.ctx('ctx value') to transfer contextual information, and get it by ctxValue in the next guard middleware. The guard middleware is executed from outside to inside, left to right.
And call next.end() to ignore remaining middleware.
">
<GuardConfigProvider><GuardProviderfallback={<div>loading...</div>}guards={((to,from,next)=>{next.end()},()=>{console.log('will not be called')})}><GuardedRoutes><GuardedRouteguards={()=>{console.log('will not be called')}}element={<div>foo</div>}path="/foo"/></GuardedRoutes></GuardProvider></GuardConfigProvider>
The GuardConfigProvider has configuration about routing, should not be used more than one in an app, make sure it's at the topmost level inside the Router (BrowserRouter and HashRouter).
And it provides APIs for whether to run guard middleware and whether to display the fallback element:
loading2...}>
bar
}
path="/bar/*"
>
baz} path="/bar/baz" />
">
<GuardConfigProvider><GuardProviderfallback={<div>loading...</div>}><GuardedRoutes><GuardedRouteelement={<div>foo</div>}path="/foo"/><GuardProviderfallback={<div>loading2...</div>}><GuardedRouteelement={<div>
bar
<Outlet/></div>}path="/bar/*"><GuardedRouteelement={<div>baz</div>}path="/bar/baz"/></GuardedRoute></GuardProvider></GuardedRoutes></GuardProvider></GuardConfigProvider>
The GuardedRoute component acts as a replacement for the default Route component provided by React Router, allowing for routes to use guard middleware and accepting the same props as regular Route.
The useGuardedRoutes hook acts as a replacement for the default useRoutes hook provided by React Router, and additionally provides fallback and guards properties for each member.