Data Mutation and Server Actions
Answered
Munchkin posted this in #help-forum
MunchkinOP
I am new to server actions, i like the concept and i try to implement it into my app to remove a bit of my API hell :D.
Beside server actions i mainly use SWR for data fetching and mutation but i struggle with mutation in combination with server actions.
For example:
In my app i use SWR to fetch a list of objects over my API.
The objects are displayed and can be modified.
Each update/insert/delete will call a server action to update the data in database and also mutate the memory of useSWR to save performance (and not refetch all the data again).
I would like to remove SWR completely but i dont know how to handle it without to haveing refetch my data after the data was modified.
What is best practise for this?
Beside server actions i mainly use SWR for data fetching and mutation but i struggle with mutation in combination with server actions.
For example:
In my app i use SWR to fetch a list of objects over my API.
The objects are displayed and can be modified.
Each update/insert/delete will call a server action to update the data in database and also mutate the memory of useSWR to save performance (and not refetch all the data again).
I would like to remove SWR completely but i dont know how to handle it without to haveing refetch my data after the data was modified.
What is best practise for this?
Answered by aardani
const { data, mutate, error } = useSWRImmutable(
["/api/v1/foodunits", foodId],
([url, foodId]: [string, string]) =>
getFoodID(id) // <-- server action
);this is how i would've set it up in React Query
17 Replies
in most sense useSWR is enough to make sure your data stays updated in next.js. Caching in native next.js appdir alone is pretty weird and not yet fully polished yet
Hence, its a good idea to use stale data manager in order to keep data fresh, like RQ or useSWR
Its also not a bad idea to delegate data update to useSWR or RQ since that means we don't have to re-render the components when a data change. Especially if the data changes often
MunchkinOP
Thank you for your answer. But can i fetch Data using SWR and Server Actions together?
I haven't tried but knowing that useSWR is similar to React-Query, it should be possible
MunchkinOP
okay, because i couldnt find any ressources and when i try it by myself i get a error
simply because useSWR still needs a fetching solution just like React-Query and Server Action is one of the available fetching solution other than fetch() or axios
may i see the part where you used useSWR with server action? i might or might not help
MunchkinOP
ah okay, i think i got it!
This is part on Client Component:
const { loading, error, data: foodUnitsData } = useFoodUnits(food.id);
export default function useFoodUnits(foodId: string) {
const { data, mutate, error } = useSWRImmutable(
["/api/v1/foodunits", foodId],
([url, foodId]: [string, string]) =>
fetch(`${url}?foodId=${foodId}`).then((res) =>
res.json()
)
);
const loading = !data && !error;
return {
loading,
error,
data: data,
mutate,
};
}@Munchkin This is part on Client Component:
ts
const { loading, error, data: foodUnitsData } = useFoodUnits(food.id);
export default function useFoodUnits(foodId: string) {
const { data, mutate, error } = useSWRImmutable(
["/api/v1/foodunits", foodId],
([url, foodId]: [string, string]) =>
fetch(`${url}?foodId=${foodId}`).then((res) =>
res.json()
)
);
const loading = !data && !error;
return {
loading,
error,
data: data,
mutate,
};
}
const { data, mutate, error } = useSWRImmutable(
["/api/v1/foodunits", foodId],
([url, foodId]: [string, string]) =>
getFoodID(id) // <-- server action
);this is how i would've set it up in React Query
Answer
MunchkinOP
Thank you, i will try it later. I have a call now. I will write if it worked and in case i mark it as solution.
You're welcome, do let me know if it doesn't work
MunchkinOP
Hey again,
i didnt got it to work.
The problem is, that:
so my client component chain looks like this:
and my server action like this:
as expected, i cant pass a object from server to client component:
i didnt got it to work.
The problem is, that:
const { data, error } = useSWR(key, fetcher)This is the very fundamental API of SWR. The fetcher here is an async function that accepts the key of SWR, and returns the data.
https://swr.vercel.app/docs/data-fetching
so my client component chain looks like this:
...
const { loading, error, data: foodUnitsData } = useFoodUnits(food.id);
...
export function useFoodUnits(foodId: string) {
const { data, mutate, error } = useSWRImmutable(
["foodunits", foodId],
([url, foodId]: [string, string]) =>
readFoodUnits(foodId).then((res) => res.json())
);
console.log("data:", data);
const loading = !data && !error;
return {
loading,
error,
data: data,
mutate,
};
}and my server action like this:
const API_ENDPOINT = process.env.API_ENDPOINT;
const API_KEY = process.env.API_KEY;
export const readFoodUnits = (foodId: string) => {
return fetch(
`${API_ENDPOINT}/foodunits?apiKey=${API_KEY}&foodId=${foodId}`,
{
method: "get",
headers: {
"content-type": "application/json",
accept: "application/json",
},
}
);
};as expected, i cant pass a object from server to client component:
Warning: Only plain objects can be passed to Client Components from Server Components. Response objects are not supported.
{: Response}
^^^^^^^^MunchkinOP
yea i tried that aswell
i get the data flow to useSWR back but then there is something happening wrong, i will check the chain again
i get the data flow to useSWR back but then there is something happening wrong, i will check the chain again
MunchkinOP
i got it!! omg what a silly mistack
i forgot to change the hook aswell...
so the working example looks like this
server action:
client component:
Thanks again.
i forgot to change the hook aswell...
so the working example looks like this
server action:
const API_ENDPOINT = process.env.API_ENDPOINT;
const API_KEY = process.env.API_KEY;
export const readFoodUnits = (foodId: string) => {
return fetch(
`${API_ENDPOINT}/foodunits?apiKey=${API_KEY}&foodId=${foodId}`,
{
method: "get",
headers: {
"content-type": "application/json",
accept: "application/json",
},
}
).then((res) => res.json());;
};client component:
...
const { loading, error, data: foodUnitsData } = useFoodUnits(food.id);
...
export function useFoodUnits(foodId: string) {
const { data, mutate, error } = useSWRImmutable(
["foodunits", foodId],
([url, foodId]: [string, string]) =>
readFoodUnits(foodId)
);
console.log("data:", data);
const loading = !data && !error;
return {
loading,
error,
data: data,
mutate,
};
}Thanks again.