steve123
steve123

Reputation: 385

Sheet as server component / how to fetch data in sheet component Next.js radix ui

I have a client component, which hosts inside a sheet component (which will be a client too because the parent component is a client component).

WorkoutGrid.tsx:

const WorkoutGrid = ({ trainingPlan }: { trainingPlan: TrainingPlan }) => {
  const [expandedWorkoutIndex, setExpandedWorkoutIndex] = useState<
    null | number
  >(null);

  const handleExpandClick = (index: number) => {
    setExpandedWorkoutIndex(expandedWorkoutIndex === index ? null : index);
  };
 

  return (
    <DashboardContainer
      type="workouts_program"
      backLink="/workouts"
      props={
        <Button asChild variant="outline">
          <Link href={""}>Edit</Link>
        </Button>
      }
    >
      <div className="grid gap-6 sm:grid-cols-1 lg:grid-cols-2 xl:grid-cols-3">
        {trainingPlan.workouts.map((workout, index) => (
          <Card key={workout.trainingName} className="rounded-lg border">
            <CardHeader>
              <div className="flex justify-between gap-x-4">
                <h2 className="text-2xl font-bold">{workout.trainingName}</h2>
                <WorkoutSheet
                  DataItem={DataItem}
                  customTrainingPlanId={trainingPlan._id}
                  workoutId={workout._id}
                />
..other data rendering
        </DashboardContainer>
      );
    };

the component renders a WorkoutSheet, which is this one:

WorkoutSheet.tsx

  const getWorkout = async () => {
    setIsLoading(true);
    setError(null);
    try {
      const URI = `custom-training-plans/${customTrainingPlanId}/${workoutId}`;
      const method = "GET";
      const res = await makeServerRequestFromClient({ URI, method });
      setWorkout(res.data);
    } catch (err: any) {
      console.error("Failed to fetch workout:", err);
      setError("Failed to fetch workout data. Please try again.");
    } finally {
      setIsLoading(false);
    }
  };

return (
    <Sheet>
      <SheetTrigger asChild>
        <Button variant="outline" onClick={getWorkout}>
          View Details
        </Button>
      </SheetTrigger>
      <SheetContent className="py-4">
        {isLoading ? (
          <div>Loading...</div> 
        ) : error ? (
          <div>{error}</div>
        ) : workout ? (
          <>
...rendering sheet data
)

so my question is, is it possible to make somehow the workoutsheet a server component? i want to fetch data as in nextjs with regular fetch without the useState. but, as the parent component is a client component, is it possible?

Upvotes: 0

Views: 46

Answers (1)

Patrick Albrecht
Patrick Albrecht

Reputation: 36

Yeah it is possible to render a server component inside a client component. The key to do that is render the server component in side the client component as a child. In your case there is some refactoring needed.

You have to create the card component(client component) with the expand logic and only renders the children if its expended. Then you should move the Dashboard component with the loop inside a server component. Inside the loop you can now use the new Card Component and pass the Workoutsheet as children prop.

export function ExpendCard({title: string}, children:any){
  const [expand,setExpend] = useState(false
  return(
  <Card key={title} className="rounded-lg border">
        <CardHeader>
           <button onClick=(()=> setExpand(expand))>
             {title}
           </button>
           {expand ? children : null}
        </CardHeader>
  </Card>
  )
}

Workoutsheet

const WorkoutGrid = ({ trainingPlan }: { trainingPlan: TrainingPlan }) => {
  return (
    <DashboardContainer
      type="workouts_program"
      backLink="/workouts"
      props={
        <Button asChild variant="outline">
          <Link href={""}>Edit</Link>
        </Button>
      }
    >
      <div className="grid gap-6 sm:grid-cols-1 lg:grid-cols-2 xl:grid-cols-3">
        {trainingPlan.workouts.map((workout, index) => (
          <ExpandCard title={workout.trainingName}>
                <WorkoutSheet
                  DataItem={DataItem}
                  customTrainingPlanId={trainingPlan._id}
                  workoutId={workout._id}
                />
                ..other data rendering
           </ExpandCard>
        </DashboardContainer>
      );
    };

Upvotes: 0

Related Questions