tata1mg / catalyst-core

https://catalyst.1mg.com
MIT License
11 stars 0 forks source link

What are some common usecases where you would define clientFetcher and serverFetcher both? #11

Open saurabhdaware opened 2 days ago

saurabhdaware commented 2 days ago

Saw this in the documentation-

image

My initial expectation from the names clientFetcher and serverFetcher API was that serverFetcher will run on server (so I can fetch some initial data) and then clientFetcher runs post mount where I can fetch some additional data different from what I have on server.

From the current behaviour, it seems like these are more of a getInitialClientData / getInitialServerData kind of functions which let you set the initial data and depending on navigation / load / back button click / etc, either one of them is executed.

Case 1: I define clientFetcher and serverFetcher both

In this case I was wondering, in which scenarios would you want your page to look different if it's page load vs client side navigation? wouldn't the page have same products and data fetching logic on both server and client scenario?

These concerns could be because its a bit different way to fetch data than what is defined in other frameworks so could be about familiarity as well. The behaviour just looks a little bit error prone in the first sight.

Case 2: I only define serverFetcher

Here, my page works fine on page load but does not load anything on navigation (which I understand from tech perspective that its client navigation) but from consumer-side, it seems a bit unexpected because while developing the app, I see things working as expected on page load but then while specifically testing the client navigation, it suddenly doesn't work.

This might be something that is initially not intuitive but later gets intuitive as people get more familar with framework.

But what would be cooler is if these pages have server navigation by default (might be possible with react server components although I haven't explored it much). Then navigation will also fetch these products


Other than this, everything looks super cool and super well built to me. I love how many edge cases are already covered. The treeshaking also seems to work fine which I initially thought would break seeing this API and love to see that serverFetcher gets clipped out from client-side code 🫡 ❤️

sauravvarma commented 2 days ago

I think you’re spot on here with the initial assumption and 1mg works on the same pattern even now.

The team’s mental model so far has been that functions being executed in the serverFetcher scope should always be a subset of clientFetcher. This would also mean that clientFetcher would have to bail out on functions that were already executed successfully in serverFetcher. Right now, this seems to be something the developers will have to ensure by reading data from the router and manually ignore that subset of operations.

As you pointed out, yes, it’s in an ambiguous state right now as we figure out the right data fetching mechanism for RSC but the bigger concern is still the one I mentioned above and whether we should offload it to the devs.

Case 1: If people end up defining the same things in serverFetcher and clientFetcher because of this quirky behaviour, we should eventually bridge them as one function that runs in both domains. I’m not a fan of it personally, I’d want to keep the server and client distinction.

Case 2: we would have to keep reverting to a server navigation for this to work as expected everywhere.

Do you think we should implement the pattern we use internally back into Catalyst?

saurabhdaware commented 1 day ago

I think both usecases might be valid in that case. Personally what your internal behaviour is seems more predictable because I get a predictable output irrespective of how I ended up on that page (either with load, client navigation, server navigation, etc)

This would also mean that clientFetcher would have to bail out on functions that were already executed successfully in serverFetcher

I'm guessing this usecase exists because in scenarios like client-navigation, server data fetching would not run.

One way would be having that as an option?

Homepage.clientFetcher = ({ isFetchedOnServer }) => {
  if (isFetchedOnServer) {
    // data is already fetched on server
    return;
  }

  // fetch again
} 

Homepage.serverFetcher = () => {}

Or somehow always execute serverFetcher

Or you can always make an API call to server and execute the serverFetcher. So that scenario is never there where only clientFetcher executes. Although this would mean every navigation is an API call. You might be able to cache these API calls and save some time maybe 🤔