Data fetching
Answered
Blue Picardy Spaniel posted this in #help-forum
Blue Picardy SpanielOP
I have some data that I'm fetching on the server and showing to the client. I have a button which adds new data via server actions but what's the industry standard to update the data on the client?
66 Replies
many people use a clientside fetching library for that like SWR or react query. I really recommend you to use one. With them you have more control over your data
Blue Picardy SpanielOP
im not too familar with SWR or react query but would you recommend keeping client side state? so when i add new data via RSC i can just add to my already existing client side data
Tibetan Spaniel
can't you save your fetched data from server into useState, then just update the state
Blue Picardy SpanielOP
yeah thats what i was asking here
Tibetan Spaniel
owh, sorry
Blue Picardy SpanielOP
np, is that industry standard and recommended? im just trying to go about the best solution
Tibetan Spaniel
I'll try to answer.
I don't know the industry standard, but actually it usually depends on your use case, like how big is the project.
I think u should consider if you really don't need to revalidate data from the server? And is it only one user at one time doing the update?
Adding to the existing client side data will result in faster ui, but i think , in general it's better and recommended to fetch new update from server (revalidating).
I don't know the industry standard, but actually it usually depends on your use case, like how big is the project.
I think u should consider if you really don't need to revalidate data from the server? And is it only one user at one time doing the update?
Adding to the existing client side data will result in faster ui, but i think , in general it's better and recommended to fetch new update from server (revalidating).
and, you've read this docs right
https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations
https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations
yes, you can either combine them or keep them updating. Revalidating everytime the page again and again when new data comes in like aryomuzakki mentioned is not recommended, because your page would be slower like that
Blue Picardy SpanielOP
so the best way is to update client state?
is the data passed down from a ssr component?
Blue Picardy SpanielOP
yeah
so have the data in a useState
the initial value will be the data from the ssr component
Blue Picardy SpanielOP
what if i need to pass data between client components?
then watch with useEffect for the passed down data and set the new state if it updates
Blue Picardy SpanielOP
wait wdym
import { useEffect, useState } from "react";
export default function YourComponent({
yourData
}: {
yourData: any
}) {
const [data, setData] = useState(yourData);
useEffect(() => {
setData(yourData);
}, [yourData]);
return (
<>
{data}
</>
)
}
yourData in this case always comes from the initial ssr value
u can pass that down to how many components u want
Blue Picardy SpanielOP
the SSR data is fetched once when the page loads so it wont update
what?
useState data will update when u trigger revalidatePath with server action
Blue Picardy SpanielOP
wait whats revalidatePath
Blue Picardy SpanielOP
let me show u my current setup
oh i was thinking u know
Blue Picardy SpanielOP
server component:
client component:
client component:
export default async function GlobalBanPortalPage() {
const globalBans = await GlobalBanCollection.find({ }).toArray();
return (
<GlobalBans globalBans={globalBans} />
);
}
client component:
export default function GlobalBans({
globalBans
}: {
globalBans: WithId<DbGlobalBan>[]
}) {
const [data, setData] = useState<WithId<DbGlobalBan>[]>(globalBans);
return (
<NewGlobalBan setData={setData} />
// display global bans with data
);
}
client component:
export default function NewGlobalBan({
setData
}: {
setData: React.Dispatch<React.SetStateAction<WithId<DbGlobalBan>[]>>
}) {
function banUser() {
setData(prev => [...prev, {
_id: offenderId,
offense,
evidence,
notes,
moderatorId: user.id,
date: new Date()
}]);
}
}
yeah in this case u are only updating the value via clientside
Blue Picardy SpanielOP
nono i have server logic too
i just cut it out bc its too much
but is this good for the client
yeah looks good
Blue Picardy SpanielOP
so whats with the useeffect
u basically listen for globalBans value to change
and update your state with the new value
Blue Picardy SpanielOP
uhh all i have for the server is triggering a server action from the client that updates the database
if u trigger this after doing your operations all ssr components in the current path will refetch the data
and useState is on clientside so u have to manually listen for changes and set the new value
Blue Picardy SpanielOP
will that mean i dont have to pass setData to my NewGlobalBan component?
and instead i can just use useEffect?
Blue Picardy SpanielOP
wdym? setData is useState
well no shit im just saying that banUser is only updating the state on clientside so i was saying that u can move this into your action and update your db or whatever
Blue Picardy SpanielOP
holy shit... that's so much easier than what ive been doing wtf?
Blue Picardy SpanielOP
what would that look like?
import {useFormState} from "react-dom";
import {handleRevalidate} from "@/actions/handleRevalidate";
export default function useRevalidator(path: string) {
const [state, action] = useFormState(handleRevalidate, {
revalidated: false,
now: Date.now(),
message: '',
});
const formData = new FormData();
formData.append('p', path);
async function revalidate(isInterval: boolean = false, interval: number = 1000) {
if (isInterval) {
const intervalId = setInterval(() => {
action(formData);
}, interval);
return () => clearInterval(intervalId);
} else {
action(formData);
}
}
return {
state,
revalidate,
}
}
"use server";
import {revalidatePath} from "next/cache";
export const handleRevalidate = async (prevSate: any, formData: FormData) => {
const path = formData.get('p')?.toString();
if (!path) return {revalidated: false, now: Date.now(), message: 'Path not valid'};
revalidatePath(path);
return {revalidated: true, now: Date.now()};
}
there we go
magic
Blue Picardy SpanielOP
o.o that looks complicated aha
nah its easy so basically im imitating a server action request and just revalidating the passed in path
ive built in a interval feature so i can do some polling action without sockets
Blue Picardy SpanielOP
well thanks for the help man, you've made my life a lot easier. i knew there was a better way
no problem
u can mark my answer as solution if that helped u 👍
Blue Picardy SpanielOP
i have looked at revalidate path before, it's come up a lot. i tried it once and it did nothing so i never thought anything of it haha, didn't know i had to use useEffect
👍