NextJS에서 Follow Button UI 구현 예시

June 11, 2024

NextJS에서 Follow Button UI를 구현한 예시

NextAuth, Prisma를 사용한다고 가정 하에 Follow Button UI를 구현

//FollowButton.tsx
interface Props{
 targetUserId: string;
}

export default async function FollowButton({targetUserId}:Props){
 const session = await getServerSession(authOptions);
 const currentUserId = await prisma.user.findFirst({where:{email:session?.user?.email!}}).then(user=>user?.id!)!
 const isFollowing = await prisma.follows.findFirst({where:{followerId:currentUserId, followingId:targetUserId}})

 return <FollowClient currentUserId={currentUserId} targetUserId={targetUserId} isFollowing={!!isFollowing}>
}
// FollowClient.tsx
"use client";
import { useRouter } from "next/navigation";
import { useState, useTransition } from "react";
import { follow, unfollow } from "./action";

interface Props {
  currentUserId: string;
  targetUserId: string;
  isFollowing: boolean;
}

export default function FollowClient({
  currentUserId,
  targetUserId,
  isFollowing,
}: Props) {
  const router = useRouter();
  const [isPending, startTransition] = useTransition();
  const [isFetching, setIsFetching] = useState(false);
  const isMutating = isFetching || isPending;

  const handleFollow = async () => {
    setIsFetching(true);
    await follow(currentUserId, targetUserId);
    setIsFetching(false);
    startTransition(() => {
      router.refresh();
    });
  };

  const handleUnfollow = async () => {
    setIsFetching(true);
    await unfollow(currentUserId, targetUserId);
    setIsFetching(false);
    startTransition(() => {
      router.refresh();
    });
  };

  return (
    <button
      onClick={isFollowing ? handleUnfollow : handleFollow}
      disabled={isMutating}
    >
      {!isMutating ? (isFollowing ? "Unfollow" : "Follow") : "..."}
    </button>
  );
}
// action.ts
"use server";
import prisma from "../lib/prisma";
import { revalidatePath } from "next/cache";
export const follow = async (currentUserId: string, targetUserId: string) => {
  await prisma.follows.create({
    data: {
      followerId: currentUserId,
      followingId: targetUserId,
    },
  });
  revalidatePath("/some-path");
};

export const unfollow = async (currentUserId: string, targetUserId: string) => {
  await prisma.follows.delete({
    where: {
      followerId_followingId: {
        followerId: currentUserId,
        followingId: targetUserId,
      },
    },
  });
  revalidatePath("/some-path");
};