在接下来的14中说明服务器和客户端组件之间的两种方式

问题描述 投票:0回答:1

我正在尝试将状态从客户端组件提升到服务器组件,在服务器上执行一些操作,然后通过 props 将状态从服务器传回到客户端。

我正在使用 Next 14、Shadcn-ui、React-hook-form 等创建一个预订系统,这意味着我的表单必须位于客户端组件中,并且我所有的数据获取都位于服务器组件中。

我想要做的是让用户使用日期选择器选择一天,将其传递给服务器,服务器获取当天的预订并计算哪些时间段是空闲的,然后将这些时间段传递回客户端以填充组合框。

看图

我最接近的是状态上升,但我只能得到一个 Promise 回来。这就是我的代码的样子。

服务器组件(父组件)

export type GetAvailableSlotsType = (date: Date) => Slot[];

export default async function NewBookingsPage() {
  const getAvailableSlots: GetAvailableSlotsType = async (date) => {
    "use server";
    console.log(`Date: ${date}`) // Shows correct date
    // Do some logic
    return availableSlots
  }
  return (
    <NewBookingForm getAvailableSlots={getAvailableSlots} />
  )
}

客户端组件(子)

import { GetAvailableSlotsType } from "../page";

type NewBookingFormProps = {
  getAvailableSlots: GetAvailableSlotsType;
};

export default function NewBookingForm({
  getAvailableSlots,
}: NewBookingFormProps) {
  // Some form schema stuff

  const availableSlots = getAvailableSlots(form.watch("date"));

  return (
    <form>
      // render form
    </form>
  )

就像我说的,子组件中的 availableSlots 作为承诺实现并且不可用,尽管从 getAvailableSlots 返回一个很好的可用对象形状。

提前致谢。

reactjs typescript next.js state react-props
1个回答
0
投票

服务器组件是静态无状态组件,可以视为纯函数,旨在生成无需 JavaScript 的 UI。子组件不能按照您在图表中的步骤 2 中描述的方式影响父服务器组件。

此外,您没有必要将

getAvailableSlots
服务器操作传递给子组件,您可以将其单独放在一个文件中(请参阅 Next 文档中的 客户端组件服务器操作约定)并直接在任何组件中使用它您希望将其视为异步函数(请参阅 Next 文档中的非表单元素中使用的服务器操作)。

但是,在您的情况下,由于需要传递日期,该模式将需要传递 formData ,建议使用

useTransition
来具有挂起状态

当您正在设计具有异步数据获取的交互式组件(组合框)时,您不应将服务器组件用于此目的。例如,如果您要根据当前 URL 显示可用性的静态列表,则服务器组件将完美适合此用例。

综上所述,您可以将图中的“服务器组件”替换为“服务器操作”,这是正确的。从 Next13 到 Next14 的重大思维转变是服务器操作不需要服务器组件,因此可以随意在服务器端组件之外使用它们:)

这是对应该有效的代码的一般重构:

服务器操作

export type GetAvailableSlotsType = (date: Date) => Slot[];

"use server";
export default async function getAvailableSlots(date: Date): GetAvailableSlotsType {
  console.log(`Date: ${date}`) // Shows correct date
  // Do some logic
  return availableSlots
}

客户端组件

import { useEffect, useState, useTransition } from "react";

export default function NewBookingForm() {
  // Some form schema stuff
  const [isPending, startTransition] = useTransition();
  const [availableSlots, setAvailableSlots] = useState([])

  const date = form.watch("date")
  useEffect(() => {
     startTransition(async () => {
        const slots = await getAvailableSlots(date);
        setAvailableSlots(slots);
     })
  }, [date]);

  const availableSlots = getAvailableSlots(form.watch("date"));

  return (
    <form>
      {/* render form */}
      {/* render combobox somewhere, you can render a loader with isPending inside the combobox */}
      <ComboBox choices={availableSlots} isPending={isPending} />
    </form>
  )

如果您还有任何疑问,请随时询问。

祝您项目成功!

© www.soinside.com 2019 - 2024. All rights reserved.