Open steinybot opened 7 months ago
I realised that the react router RouterProvider
is behaving differently the second time around because the state has already been set. When the router is recreated it's state has initialized = false
but the state of the RouterProvider
has initialized = true
. See https://github.com/remix-run/react-router/issues/11300.
usePreloadedQuery
will log a warning if it is passed a preloaded query that was created with a different environment than the one that is currently in context. It says that this will become a hard error in future. This seems reasonable however this is going to cause a pretty big problem when using relay with react-router.Consider we have something like:
Where
MutableRelayEnvironment
is something like:That can be update elsewhere like:
And a naive router such as:
createBrowserRouter
will asynchronously runstartNavigation
that will load the data. It ends up yielding to the render of theRouterProvider
which has auseLayoutEffect
that will subscribe to the router to get the loaded data (which includes the preloaded queries). The first time around no data has been loaded and so the endpoint routes are not rendered. The layout effect is run and then it returns back tostartNavigation
which now provide the loaded data to each subscriber. TheRouterProvider
now rerenders with the new state and renders each route. Finally the routes callusePreloadedQuery
and all is well.The issue is that when the environment changes,
MyRouter
rerenders and callscreateBrowserRouter
again repeating the above process. However this time whenstartNavigation
yields andRouterProvider
renders it will have the data that was loaded last time which include the preloaded queries with the old environment. Loaded data exists and so the routes will be rendered this time. NowusePreloadedQuery
will see that the environment from the context and the query do not match and we get the warning.RouterProvider
will rerender like before and get a new set of preloaded queries with the updated environment and so is currently ok.Once this becomes a hard error this is going to break pretty spectactularly and I can't think of a way for end users to avoid it except perhaps manually checking the environment and intentionally throwing and catching that in an error boundary at the root of the router and relying on it rerendering. That might work but the logs will still be full of errors since React does not provide a way to supress handled errors (https://github.com/facebook/react/issues/15069).
I hope that it will be possible to work with react-router to make this work before making this a hard error in relay.
See here for the original issue that I reported with @loop-payments/react-router-relay: https://github.com/loop-payments/react-router-relay/issues/14
Reproduction: https://github.com/steinybot/react-router-relay/blob/bug/stale-environment-2/examples/todo/src/MyRouter.tsx