Next.js Discord

Discord Forum

set metadata in server components

Unanswered
Sage Thrasher posted this in #help-forum
Open in Discord
Sage ThrasherOP
export default async function Page({ params }: { params: { id: string } }) {
    const data = await fetchProfile({ id: params.id }).catch(() => null);
    if (!data) return;

    // metadata title as 'data.name'


how can i make the page title 'loading' then once the fetch is complete, it is set to data.name

47 Replies

@Sage Thrasher i saw this, but then i would have to refetch the data in this function
you can use the react cache so the request will be deduped. Like that you make one request and the result will be used twice (or more times)
@B33fb0n3 you can use the react cache so the request will be deduped. Like that you make one request and the result will be used twice (or more times)
Sage ThrasherOP
yeah i was thinking that but i didn't know if there was a more efficent way to parse the data
@B33fb0n3 it's the recommended way on fetching stuff. Read here: https://nextjs.org/docs/app/building-your-application/data-fetching/patterns#fetching-data-where-its-needed Or here: https://nextjs.org/docs/app/building-your-application/caching#request-memoization > ... without worrying about the performance implications of making multiple requests for the same data.
Sage ThrasherOP
@B33fb0n3 i use caching on most my fetches, however when a user logs into the website for the first time with their discord account, thats the only time i get their data, is there a similar function on authjs to the session one but only calls once per browsing session or something similar so i can actively refetch their new data without using up a lot of storage for cached data or getting ratelimited by discord
Sage ThrasherOP
also in addition, say 3 people have loaded a page and therefore have data cached for an hour, but someone does something to update the data, how can i make the data be refetched and the page reupdated?
@Sage Thrasher also in addition, say 3 people have loaded a page and therefore have data cached for an hour, but someone does something to update the data, how can i make the data be refetched and the page reupdated?
you can use [unstable_cache](https://nextjs.org/docs/app/api-reference/functions/unstable_cache) to be able to cache third party (discord api) results directly and cache them for x time. If you call the discord api via [fetch](https://nextjs.org/docs/app/api-reference/functions/fetch) you don't need to use the unstable_cache. Inside the fetch you can directly revalidate after x seconds like:
  // This request should be cached with a lifetime of 10 seconds.
  const revalidatedData = await fetch(`https://...`, {
    next: { revalidate: 10 },
  })
when the user clicks submit, a function calls a server action which posts data to my other api
once thats done, i want to only refresh the data for a specific fetch on the page
right now, i have to wait until revalidation timer and refresh
but i dont want to wait or refresh
Sage ThrasherOP
    const response = await fetch(endpoint, {
        method: 'POST',
        headers: {
            'authorization': process.env.API_KEY,
            'content-type': 'application/json'
        },
        body: JSON.stringify({
            ...patchedData,
            userId: session.user.discordId
        })
    });

    if (!response.ok) {
        const errorText = await response.text();
        throw new Error(parseJson(errorText)?.message ?? response?.statusText ?? 'Something went wrong');
    }

    revalidateTag('fetchProfileReviews');
    revalidatePath(`/profile/${profile.id}`);

    return;

this is what im currently doing but it doesn't refresh the data on the page (this is inside the server action which i call from a client component)
once it's completed, you can do a router.refresh() from where you called the server action
@Arinji once it's completed, you can do a router.refresh() from where you called the server action
Sage ThrasherOP
okay so the data refreshes on the page, however new elements aren't inserted using this

im making a comment feature where you can comment on the profile, once someone comments, the numbers (stats) increases however the comment isn't displayed unless i refresh the page
Sage ThrasherOP
here another example, you can see on initial load, the data is fetched then here is logged, after router.refresh() here is logged again but the data isnt
i presume i need to put a dependency in the useEffect then change this value when i refresh so this useeffect is ran again?
@B33fb0n3 R u using a client side fetching library like SWR or react query?
Sage ThrasherOP
im just using fetch from next
@Sage Thrasher im just using fetch from next
Use a clientside fetching library to handle comments. Or only add the new comment clientside to display it
im just wondering
i think the issue is because my useeffect isnt emitting on refresh
@Sage Thrasher what difference would this make ?
with clientside fetching libraries you can control your data easily. Without it is still possible, but way harder
Sage ThrasherOP
which would you recommend?
also i am refreshing in a different component to where i am fetching
I like to use react query, because it has more functionallity then swr
Sage ThrasherOP
export async function ProfileBody(...) {
...

  return (
    <LeaveComment guildId={props.profile.id} />
    <Comments guildId={props.profile.id} totalReviews={reviews} />
  )
}


// LeaveComment.tsx (where you send comments)
export default function LeaveComment(...) {
  const router = useRouter();
  const { data: session } = useSession();
  const [rating, setRating] = useState<number>(0);
  const [text, setText] = useState<string>('');
  const [error, setError] = useState<string>();
  const [state, setState] = useState<string>('default');

  if (!session) return <></>;

  async function handleSendComment() {
    if (!props.reply  && (rating <= 0 || rating > 5)) return setError('Rating must be between 1 and 5');
    if (typeof text !== "string" || text.trim().length <= 10) return setError('Content must be at least 10 characters');

    setError(undefined);
    setState('loading');

    try {
      await createReview({ text, rating, profileId });

      router.refresh();
      toast.success('Successful', defaultToastOptions);
    } catch (error: any) {
      toast.error(error?.message ?? 'Something went wrong', defaultToastOptions);
    }

    setState('default');
  }


// Comments.tsx (visual render of all comments)
export default function Comments(...) {
  const reviewRenderAmount = 5;
  const { data: session } = useSession();
  const [reviews, setReviews] = useState<ReviewDataResult[]>([]);
  const [likedReviews, setLikedReviews] = useState<Set<string>>(new Set());
  const [currentPage, setCurrentPage] = useState(1);
  const [targetReply, setTargetReply] = useState<string>('');
  const [totalPages, setTotalPages] = useState(Math.ceil(totalReviews / reviewRenderAmount));
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    setTotalPages(Math.ceil(totalReviews / reviewRenderAmount));
  }, [totalReviews]);

  useEffect(() => {
    const fetchReviews = async () => {
      setLoading(true);
      try {
        const result = await fetchProfileReviews(profileId, {
          offset: (currentPage - 1) * reviewRenderAmount,
          limit: reviewRenderAmount,
        });
        setReviews(result);
      } finally {
        setLoading(false);
      }
    };

    fetchReviews();
  }, [guildId, currentPage]);
}
this is the general design, LeaveComment is also referenced inside Comments for replying to comments
yea, use a clientside fetching library and then revalidate the data when the user commented. One example on revalidating data after something changes is create from me here: https://github.com/B33fb0n3/rq-profile-picture
Sage ThrasherOP
which file should i look at?
Sage ThrasherOP
also, would clientside fetching make the useEffect emit again because thats what's not happening right now
im using server actions to fetch the data as well so preferably would like to keep using them instead of the clientside fetching for the ease
yea, clientside fetching would take all the control over your data and you can easily manage it. Do you see anywhere in my project an useeffect for data fetching? 🙂
Sage ThrasherOP
ah
@Sage Thrasher is it possible to call a server action with react-query or swr?
yes, can you please take a look at my project?
@B33fb0n3 yes, can you please take a look at my project?
Sage ThrasherOP
my fault, i was looking at the docs and saw they were using links
The questions, that you currently asking are already answered in the repo that I linked. See here:
Server actions: https://github.com/B33fb0n3/rq-profile-picture/blob/main/app/ChangeProfilePictureButton.tsx#L13
Revalidation: https://github.com/B33fb0n3/rq-profile-picture/blob/main/app/ChangeProfilePictureButton.tsx#L20
@Sage Thrasher solved?