vikejs / vike-react

🔨 React integration for Vike
https://vike.dev/vike-react
MIT License
93 stars 15 forks source link

How to `vike-react-redux` ? #87

Open tbscode opened 6 months ago

tbscode commented 6 months ago

Hi saw the open pull #57 🚀, I'm very interested in something similar for redux. But adding a full abstraction over redux seems a little overkill for my case ( & annoying to maintain? )

I'd rather just be able to add a redux provider and global store to renderHtml & renderClient, whilst using vike-react but without maintaining a seperate plug-in?

Is it already possible to redux with vike-react? ( I didn't manage )

How would one integrate it? ( or does it really require a separate plugin? )

brillout commented 6 months ago

The general idea here is that vike-react should implement new hooks so that tools like Redux can be integrated in user-land and/or as a Vike extension.

For example, after @yoshi2no implemented vike-redux not only will you be able to use it, but you'll also be able to implement your own custom integration using the hooks that vike-redux uses.

In the meantime, the question is: what do you need from vike-react to be able to integrate Redux?

What you'll most liklely need is to be able to wrap the root component, for that you can see how vike-react-zustand does it. (FYI after https://github.com/vikejs/vike/issues/1283 is implemented we won't need a new Wrapper setting per tool anymore.)

Beyond a Redux wrapper, do you need something else? I guess a way to pass the Redux store from the server to the client-side?

Let me know if that all makes sense. Also, if you're up for it, PR welcome that adds /examples/redux and that accomodates vike-react to make it possible.

tbscode commented 6 months ago

Nice I'll bee looking out for vike-redux :D thanks for letting me know.

I'm currently using redux along the lines of official vike redux example

BUT instead of using +onBeforeRenderClient.tsx I use +onRenderHtml.tsx ( & +onRenderClient.tsx ) to inject the initial redux store.

As mofiying +onBeforeRenderclient.tsx causes an additional POST request when navigating clientside slowing down the navigation

You can see this behavior in the official vike redux example checking the netwok tab when navigating. ( Btw should I open this as a seperate issue possibly ? )

I've been able to completely avoid the additional POST /<page>/index.pageContext.json by setting the inital store in +onRenderHtml.tsx instead, see here

If you'd give me a hint on how to achive that whilst using vike-react I'd give it a try. Current setup works but would be improved / cleaner with vike-react so I can also wait :)

brillout commented 6 months ago

How about a new hook onAfterRenderHtml()?

tbscode commented 6 months ago

Ok interesting yes, this would also prob solve the use case I posted in #community-help on discord. I.e.: fetching data for the first SSR render, but then not re-fetching / posting to pageContext.json on client navigation.

I would still have to understand how to use this on inject the <Provider> though?

brillout commented 6 months ago

I'm not sure what you mean, but feel free to suggest something else than creating a new custom hook onAfterRenderHtml().

tbscode commented 6 months ago

What eactly would onAfterRenderHtml do? How would I add the redux <Provider> if the pageHtml is already rendered?

I'd like to:

  1. use redux, wihout modifying +onBeforeRenderClient.tsx ( as this causes the additional POST I'd like to avoid ). In best case use it combined with vike-react.
  2. Fetch data on first Page render ( to initalize the store ), but NOT use +data.ts or +onBeforeRenderClient.tsx as this also causes the additional POST on clientside navigation.
nitedani commented 6 months ago
  1. fetch data in +onBeforeRender.tsx, set it on pageContext
  2. add the provider in +Wrapper.tsx, get data from usePageContext

+Wrapper.tsx

const pageContext = usePageContext()
const [store] = useState(() => getStore(pageContext.PRELOADED_STATE))`
...
return <Provider store={store}>...</Provider>
tbscode commented 6 months ago

But this would also cause an additional POST request on client side navigation. Maybe a little example, so I'm working on a chat app:

If the user loads e.g.: /chat I would fetch all the chats for the initial render, use that to initialize the Redux store. When the user clicks a chat I do client side navigation navigate(...) to /chat/<chat-uuid>, in this case the chats are already loaded into the store, so should NOT be fetched again.

But from my experiments, as soon as I use +onBeforeRender.tsx the navigation /chat -> /chat/<chat-uuid> triggers an additional POST to /chat/chat.pageContext.json. This is make navigating significantly slower.

I think this is just inherently how +onBeforeRender.tsx behaves, so I wonder if there is instead a hook that just runs on the first server side render.

brillout commented 6 months ago

My thinking was that onAfterRenderHtml() would be called here (i.e. after the HTML is generated but before onRenderHtml() returns). Correct me if I'm wrong but, together with <Wrapper>, I think that would do the trick.

tbscode commented 6 months ago

I'm not sure if I understand correctly:

Wrapper is added to pageView in getPageElement, and there I'd initialize the store?

But if onAfterRenderHtml runs after the html is rendered, how can I still inject data to the store?

I could see how it would work with a onBeforeRenderHtml ( also before pageView creation ). So something that runs only of first SSR render but still allows to fetch & pass data for the store initalization.

Since I still think the only way to avoid that vike send a POST /<page>/page.pageContext.json request on client-side navigation ( <page>/some -> <page>/other ) is not to use +onBeforeRender.tsx, in pages/<page>/*.

Correct me if I'm wrong or let me know if I should try to further clarify, thanks for taking the time!

brillout commented 5 months ago

@tbscode See https://github.com/vikejs/vike-react/pull/96 which is similar to what I meant.

Also see how the other extensions work, e.g. vike-react-query uses <Wrapper> (it actually uses <VikeReactQueryWrapper> because <Wrapper> isn't cumulative yet).

Let me know if you still have questions. I can create a PR showcasing what I mean.

tbscode commented 5 months ago

Thanks! So afaik +onAfterRenderClient allows me:

✅ client-side page-based fetching +onAfterRenderClient ( lets me simplify the app's client fetching logic, nice! ) ❌ server-side fetching + initialize Redux store with dynamic data server-side without +onBeforeRender or +data ( as it causes POST requests on client-side navigation. )

Or is the second case possible in the current vike-react-zustand implementation?

However, I do now have a setup Redux + Vike such that:

I'd still like to migrate to vike-react at some point but don't see any benefits at the moment / I only fear that I might accidentally use some vike stuff that will be deprecated in the future.

So this isn't a high priority for me anymore! I'm happy ;)

I do have some special requirements like injecting URL params into the Redux state and passing some cookies through page context, and I (could) also achieve point 2 sorta by adding some route-based fetch calls to onRenderHtml.

Might be making some wrong assumptions about how vike works? By the way, a diagram in the docs showing the flow of which +on* hook is hit when (for the SSR scenario) would be really helpful!

brillout commented 3 months ago

We've added a new hook onBeforeRenderClient() that may (or may not) help.

Contribution welcome for:

a diagram in the docs showing the flow of which +on* hook is hit when

We've added https://vike.dev/hooks#order.