Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client side request are not cached #53

Closed
plcdnl opened this issue Jun 17, 2024 · 10 comments
Closed

Client side request are not cached #53

plcdnl opened this issue Jun 17, 2024 · 10 comments

Comments

@plcdnl
Copy link

plcdnl commented Jun 17, 2024

Hi, sorry for the disturb.

I'm using the data cache api and I was wondering if it was the normal functioning of the plugin that the client side returns undefined as the cached value.

Is there a way to make this work on the client side too?

@dulnan
Copy link
Owner

dulnan commented Jun 17, 2024

The module is specifically only made for SSR caching. Especially the unstorage dependency would have to be included in the client bundle for a seamless experience, which would not be that great. And it would then also only be compatible with the memory driver. Of course it would be possible to hardcode a memory cache into the client side code of the composable.

On the client side you already have Nuxt's own utilities such as useState or useAsyncData available to implement your own caching. For a seamless experience, useDataCache would have to pass the cached data back to the client as a payload so it's available on hydration. However, when used together with useState or useAsyncData, the same data would then be passed as payload twice.

However, I do see the value of having a single useDataCache composable that handles both server and client caching. I will keep this open to explore possible solutions.

@plcdnl
Copy link
Author

plcdnl commented Jun 17, 2024

Thank you for your quick response. The problem with useState and useAsyncData is that at the moment it should do at least one time a graphql call on client side. If the data already persist in the cache i'd like to avoid that graphql call.

I don't know if my thought is right but I hope it can be useful

@dulnan
Copy link
Owner

dulnan commented Jun 17, 2024

Yeah I know exactly what you mean! Just using useAsyncData out of the box will only return a cached value on hydration. You'd have to define your own getCachedData method in useAsyncData to make it work. That would give you the possibility to return cached data from payload. And when using transform you could also cache subsequent GraphQL calls done inside useAsyncData.

@plcdnl
Copy link
Author

plcdnl commented Jun 17, 2024

Thank you and sorry again. I know that this question can riuslt annoying.
What do you mean when you say "define my own getCachedData" method?

Do you think that a server endpoint that handle this for me can be a good solution? Or do you have an alternative idea?

🙏

@dulnan
Copy link
Owner

dulnan commented Jun 17, 2024

You can pass a getCachedData method to the useAsyncData options: https://nuxt.com/docs/api/composables/use-async-data#params

By default, the getCachedData method is this:
key => nuxt.isHydrating ? nuxt.payload.data[key] : nuxt.static.data[key].
This will only load the cached data during hydration. But you can implement it as
key => nuxt.payload.data[key] || nuxt.static.data[key]
instead, which should also work after hydration.

Note that this only works on the client side. On the server these methods are not called, if I'm not mistaken.

@plcdnl
Copy link
Author

plcdnl commented Jun 17, 2024

Wow, simpler than i thought. It works fine with subsequent calls but in the client at the first access between one page and another it is always a new graphql when I am sure that the data has already been stored with the addToCache function.

export async function useGqlData({ key, query, variables }, args) {
	const transform = args?.transform
	const options = {
		...args,
		cacheKey: key,
		transform: undefined,
	}
	const nuxt = useNuxtApp()
	const { $graphqlApi } = nuxt

	return useAsyncData(
		key,
		async () => {
			const { value, addToCache } = await useDataCache(key)

			if (value) {
				return value
			} else {
				const res = await $graphqlApi({ query, variables })
				if (res.error || res.errors || !res.data) {
					console.error(res.error || res.errors || "No data found.")
					throw new Error("Error in fetching data")
				}

				const result = transform ? transform(res.data) : res.data

				if (key) {
					addToCache(result, options.cacheTags, options.cacheExpires)
				}
				return result
			}
		},
		{
			...options,
			getCachedData: (key) => {
				return nuxt.payload.data[key] || nuxt.static.data[key]
			},
		}
	)
}

This is my custom useAsyncData

@dulnan
Copy link
Owner

dulnan commented Jul 5, 2024

I would try to move const { value, addToCache } = await useDataCache(key) outside of useAsyncData into your composable. You might also need to enable the experimental asyncContext feature of Nuxt for this to work properly. Also keep in mind you should await addToCache, because it's possible that it never stores in cache if execution continues.

@dulnan
Copy link
Owner

dulnan commented Jul 6, 2024

@plcdnl In #58 a new composable called useCachedAsyncData was implemented that now also implements a client-side cache. The plan is to also add this functionality to useDataCache in #59.

I hope to release the new composable some time next week.

@plcdnl
Copy link
Author

plcdnl commented Jul 15, 2024

Wow! Incredible work. Thank you ! 🙏

@dulnan
Copy link
Owner

dulnan commented Aug 25, 2024

As this has already been released in the last release, I'm going to close this issue.

@dulnan dulnan closed this as completed Aug 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants