Context:
I developed a website using Next13 (now updated to 14), for an educational institution, where the user is presented to a landing page with a login form. After the login, the user can access an area where he can get his college debts.
On this logged-in area, I fetch all his existents debt contracts on the /contracts page.
If he wants to renegotiate one of these debts, a link redirects him to the /negotiation page, where I fetch a simulation for this debt negotiation (the simulation endpoint returns the original price of the debt, how much of deduction the student will get based on the payment choices, the price of the debt after deductions, etc...).
This simulation endpoint needs the clicked contract data, so I also fetch the data of the chosen contract (using the contractId, which I've sent on the link and get on this page via url params).
After the user set his negotiation options (payment method, how many installments, etc...), I send him to an /overview page. This page needs both the contract and the simulation data to show to the user the overview of the agreement. So I fetch (again) the contract data, and the simulation data.
The application have one more page after that, but these ones can summarize the problem.
Notes:
- I didn't developed the backend.
- All the data are fetched via API using Next's fetch.
- I'm using Server Actions to fetch and send data, although the application do not have any forms inside the logged-in area (if it's a problem, please let me know).
- I fetch the data on the page.tsx, and all pages are React Server Components
Basically the flow of the application is:
- /contracts/page.tsx (React Server Component)
- Fetch the data of all the user's contracts
- Send the data to children components (most are client-components)
- List the contracts
- Send the user to /negotiation?contractId=id-of-clicked-contract
- /negotiation/page.tsx (React Server Component)
- Fetch the contract data from API
- Fetch the simulation data from API
- Send the data to children components (most are client-components)
- Send the user to /overview
- /overview/page.tsx (React Server Component)
- Fetch the contract data from API
- Fetch the simulation data from API
- Send the data to children components (most are client-components)
Problem Nº 1
The first problem is that the API is really slow to return a response data due to the need of get some of the student's data from another API which we do not have access to. The simulation endpoint, for an instance, have a response time always longer than 15s, sometimes it takes more than a minute to return a response!
In order to solve this problem, after fetching both the contract and the simulation data on the /negotiation page, I stored these data inside a zustand's store, and then, on the /overview page, I would only get the data from the store, which prevented the user to experience all the loading time again to request the same data they've already requested on the previous page.
Sometimes, in local development, the zustand would not be able to get the data on the /overview page, the store would just be empty. After building and starting the application locally, this bug didn't happened a single time. On the homologation enviroment the application behaved the same way as the one I've builded locally, zustand's store would always have the data inside of it. But on the production enviroment the application behaved the same way it was behaving on development, sometimes the data would be stored, sometimes it wouldn't.
Notes
- The zustand store was successfully setting the data, which I discovered by getting the store's data right after setting it. But, on any other page, the same store seemed to have no data at all.
- I was setting and getting the store data on the server side, never inside a client component.
- After some research, I learned that zustand is not meant to store server data, only the client-side ones. But I don't have any clues why after I've built the application, the store was working perfectly. If you have some explanation to that, I'm curious to learn about it.
- I really don't want to refactor the application to be 100% client-side and make fetches inside useEffect only to be able to use contexts/zustand. But if this the best way to build this application, let me know!
Problem Nº 2
After a quick research, I found out that Next caches all the fetched data, and prevents multiple calls for the same request, so I used the same server actions ( getContract() and getSimulation() ) on different pages to fetch the data and stopped using zustand inside the application.
Which led me to a new problem. The cached data was a mess! Sometimes it would bring me data from another user which I've used to make tests previously; Sometimes, in the /overview page, it would bring me different data than the ones I'd fetched inside the /negotiation page. The application's data wasn't reliable anymore, and that's a big problem to a financial application with thousands of students trying to renegotiate their educational debts.
The only solution I had to this problem, and the one I'm still using, was to remove all the cache from Next fetches, and make the user watch the loading page for long seconds everytime he switch pages.
Note
- I tried using revalidatePath(), but nothing changed, maybe I just used it the wrong way.
- After researching, I've seen some people recommending React-Query, if you think it would solve my problem, could you tell me how to do so using my application as an example? I'm clueless about how to manage my application's cache.
The Question(s)
How to manage and store (if needed) the fetched data the best way possible using server components?
Is there a good practice to do it using Next latest updates?
Should I really be using Server Actions on this application?
How can I make sure the cached data is from the user that really owns it, and how to make sure the cached data is really updated?
Should I really fetch the data from the server-side, or is it better to do it on the client-side (I feel it's better on the server-side, but some people at work think I should do it on the client-side), and why?
Any videos, articles and any other resources will be very helpful, feel free to share!
Thank you so much for reading, and congratulations for your patience and curiosity! hahaha