-
-
Notifications
You must be signed in to change notification settings - Fork 10.5k
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature]: Router Context #9324
Comments
@jamesopstad Thanks for the request! This is definitely something on our radar and we've got a few APIs in mind that we're discussing internally. I'll update this issue as we have any more concrete information 👍 |
Hey @brophdawg11! I think this might be a related problem: What are you supposed to do when you have a provider, say ReactDOM.createRoot(document.getElementById("root")).render(
<BrowserRouter>
<AuthProvider>
<App />
</AuthProvider>
</BrowserRouter>
); But not sure what the equivalent would be using v6.4 data APIs. This is not possible, since const router = createBrowserRouter(
createRoutesFromElements(<Route path="/" element={<Root />} />),
);
ReactDOM.createRoot(document.getElementById("root")).render(
<AuthProvider>
<RouterProvider router={router} />
</AuthProvider>
); This is not possible, since const router = createBrowserRouter(
createRoutesFromElements(
<AuthProvider>
<Route path="/" element={<Root />} />
</AuthProvider>,
),
);
ReactDOM.createRoot(document.getElementById("root")).render(
<RouterProvider router={router} />
); This is possible: const router = createBrowserRouter(
createRoutesFromElements(
<Route
path="/"
element={
<AuthProvider>
<Root />
</AuthProvider>
}
/>,
),
);
ReactDOM.createRoot(document.getElementById("root")).render(
<RouterProvider router={router} />
); But that would require wrapping Any suggestions? |
Just use a pathless const router = createBrowserRouter(
createRoutesFromElements(
<Route element={<AuthProvider />}>
<Route path="/" element={<Root />} />
{/* More Routes here... */}
</Route>
)
) |
Easy as that! Thanks! |
I've been test driving the new data loading apis, and I like the concept but in practice I'm finding it challenging to integrate with. It feels like a feature like this might help. The use case is simple. I've got an api that uses JWT auth. What's the best way to pass the current access token (and dealing with updating it etc) into a loader. The loaders are more or less pure functions it seems. The only example I see around auth, doesn't use the Maybe there's a way to do it, but wasn't clear through my investigation this morning. For a bit more context. I'm currently using the My ideal scenario would be to be able to provide/update the access token that can be used by the data loaders for accessing protected data. Interested to see / hear about what new api's might be in the works for the data loading side. |
@timdorr I tried your option, it only works fine, when you click around the site, but when I hit refresh, or enter direct page, the loader always crashes, since msalInstance is not initialised yet. |
While this feature is being considered, I'd like to add that it'd be useful to provide a mechanism for passing values from hooks into loaders and actions. As it stands, Auth0's React SDK library only allows token values to be accessed via the |
+1. I'd really like to migrate my app to Remix (or at least react-router 6.4), but I use custom Hooks to fetch all of my data. These Hooks use an export const useGetUser = async (id: string) => {
const { apiRequest } = useSession();
return await apiRequest({
path: `identity/user/${id}`,
method: "GET",
})
}; I can't call these inside a loader. The best I can do is wrap them in Tanstack Query, and use the workaround mentioned by the OP here. Not ideal. Because the session is stored inside of React context, the solution proposed in the OP isn't quite right for me either. In a perfect world, I could do something like this: // App.tsx
const App = () => {
<SessionProvider>
{(sessionContext) => (
<RouterProvider context={{ sessionContext }}/>
)}
</SessionProvider>
} and my loader could look like this: // User.tsx
export const loader = async ({ params }, context) => {
const { apiRequest } = context.sessionContext
return apiRequest({
path: `identity/user/${id}`,
method: "GET",
})
} Am I missing any workarounds? Would love some pointers if I'm going about this the wrong way. |
This comment was marked as off-topic.
This comment was marked as off-topic.
I would like to see some type of official context api added as well. Here is what I'm currently doing to ensure my loaders and actions have access to the firebase services. It would be great to remove the import { LoaderFunctionArgs, ActionFunctionArgs } from "react-router-dom"
declare module "react-router-dom" {
interface LoaderFunctionArgs {
context: IFirebaseContext
}
interface ActionFunctionArgs {
context: IFirebaseContext
}
} import AppShell from "@components/AppShell"
import Loader from "@components/Loader"
import { ROUTES } from "@constants"
import { useFirebase } from "@Firebase"
import DashboardRoute, { DashboardLoader } from "@routes/dashboard"
import { createBrowserRouter, Navigate, RouterProvider } from "react-router-dom"
export const AppRouter = () => {
const { loading, ...context } = useFirebase()
// Wait for auth to finish loading
if (loading) {
return <Loader />
}
return (
<>
<RouterProvider
router={createBrowserRouter([
{
element: <AppShell />,
children: [
{
index: true,
path: ROUTES.Dashboard.slug,
element: <DashboardRoute />,
loader: (args) => DashboardLoader({ ...args, context }),
},
],
},
{
path: "*",
element: <Navigate to={ROUTES.Dashboard.path} />,
},
])}
/>
</>
)
}
export default AppRouter |
There's a Generally speaking though - we don't want React Context to be a dependency for data fetching - since the entire idea of the 6.4 data APIs is to decouple data fetching from rendering. In order to access client side data from a react context, it has to be handed off to a context provider somewhere higher up in the tree and by definition is then accessible from JS somehow. The solution is then to access that data from the source in JS, and not from context. But not all third party APIs currently give you easy access to some of this stuff in a non-context manner. |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
What is the new or updated feature that you are suggesting?
It would be useful to be able to set a
context
value when initialising the router that can then be accessed inloaders
andactions
.Example
Why should this feature be included?
As
loaders
andactions
cannot use React hooks, there is currently no way to access contextual data within them. A workaround suggested in this article (https://tkdodo.eu/blog/react-query-meets-react-router) is to create an additional function wrapper for eachloader
andaction
. Providing acontext
value directly when initialising the router would be a more elegant solution.The text was updated successfully, but these errors were encountered: