molefrog / wouter

🥢 A minimalist-friendly ~2.1KB routing for React and Preact
https://npm.im/wouter
The Unlicense
6.73k stars 154 forks source link

Use wouter in SSR mode and detect redirects #468

Open dide0100 opened 3 months ago

dide0100 commented 3 months ago

Hi community, my question is pretty straight forward. How do I migrate from the old static-location to the new SSR mode way of working when I need to detect redirects. I think I understand the migration but im just missing the 'record: true' part and where i can make it fit into the context.

Example: I used the old functionality in this way:

const location = staticLocationHook(req.originalUrl, { record: true });

And then i use it like

    <Router matcher={matcher} hook={location}>
        <App />
    </Router>`

and also

    const currentPath = location.history.slice(-1)[0];
    const redirected = currentPath !== req.originalUrl;

    if (redirected) {
      return { redirectTo: currentPath };
    }

Thank you in advanced

molefrog commented 2 months ago

It's not possible at the moment unfortunately. The staticLocationHook has been deprecated because it stopped working when we switched to useSyncExternalStore. The new approach to use SSR is to use ssrPath prop. In theory, we could detect redirects when the page is rendered, but that will require us to perform redirects outside of useLayoutEffect (which doesn't fire on a server). I haven't researched the implications of calling setLocation directly in render though. Will it. Will it work with Suspense?

gbettencourt commented 2 months ago

@molefrog the approach taken by react-router and other libraries (such as loadable-components) that need to track render attributes of a child during a SSR is to wrap their children in a context. The child component (in this case Redirect) would register with that context that it redirected to a given URL. That context state can then be read by users of Router to know if a redirect occurred.

Look at usages of staticContext here: https://github.com/remix-run/react-router/blob/v5/packages/react-router/modules/Redirect.js#L19

Another example, look at how extractor is used in loadable-components: https://github.com/gregberge/loadable-components/blob/main/packages/server/src/ChunkExtractorManager.js

Perhaps wouter could take a similar approach?

dide0100 commented 2 weeks ago

Thank you @gbettencourt for your post. If i understand you correctly there is no need for the library to be updated and in a way I could do this by implementing my own Context? If so could you be so kind to provide me with an example based on my code above. It would help tremendously.

gbettencourt commented 2 weeks ago

Thank you @gbettencourt for your post. If i understand you correctly there is no need for the library to be updated and in a way I could do this by implementing my own Context? If so could you be so kind to provide me with an example based on my code above. It would help tremendously.

You could implement this without library support. I did open a PR to add support directly in wouter here: https://github.com/molefrog/wouter/pull/491. That should give you an idea of how to implement outside the library. Basically you'd need to wrap your components in a custom context, then implement and use your own Redirect component that would update state on that context or navigate (if on the client). After rendering your component tree, read that context state to see if any Redirect was rendered, and redirect to that path. My updates to the README show how to do that.