You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next 14中Server与Client组件双向传态:返回Promise无法正常使用

预订系统中Server Action返回值的异步处理方案

核心问题

你调用Server Action后得到的是Promise,这是因为Server Action本质是异步函数,不能直接把返回值当作同步数组使用,必须通过异步处理逻辑解析Promise并更新组件状态。

解决方案步骤

  1. 修正类型定义
    Server Action是异步函数,所以GetAvailableSlotsType的返回值类型应该是Promise<Slot[]>,而非直接的Slot[],否则会出现类型不匹配问题。

  2. 在Client组件中处理异步逻辑
    使用useState存储可用时段和加载状态,通过useEffect监听日期选择器的变化,当日期更新时触发Server Action,解析Promise后更新状态。

  3. 添加加载与错误处理
    加入加载状态提示用户,同时捕获请求错误避免页面崩溃。

修改后的完整代码

Server Component(父组件)

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

// 假设Slot类型定义如下
type Slot = { id: string; time: string };

export default async function NewBookingsPage() {
  const getAvailableSlots: GetAvailableSlotsType = async (date) => {
    "use server";
    console.log(`Date: ${date}`);
    
    // 替换为你的实际预订记录查询与可用时段计算逻辑
    const availableSlots: Slot[] = [
      { id: "slot-1", time: "09:00-10:00" },
      { id: "slot-2", time: "10:00-11:00" },
      { id: "slot-3", time: "14:00-15:00" }
    ];
    
    return availableSlots;
  };

  return <NewBookingForm getAvailableSlots={getAvailableSlots} />;
}

Client Component(子组件)

"use client";

import { useState, useEffect } from "react";
import { useForm } from "react-hook-form";
import { GetAvailableSlotsType } from "../page";

type Slot = { id: string; time: string };
type FormValues = { date: Date };

type NewBookingFormProps = {
  getAvailableSlots: GetAvailableSlotsType;
};

export default function NewBookingForm({ getAvailableSlots }: NewBookingFormProps) {
  const { watch, register } = useForm<FormValues>();
  const selectedDate = watch("date");
  
  // 存储可用时段和加载状态
  const [availableSlots, setAvailableSlots] = useState<Slot[]>([]);
  const [isLoading, setIsLoading] = useState(false);

  // 监听日期变化,触发Server Action
  useEffect(() => {
    if (!selectedDate) return;

    const fetchSlots = async () => {
      setIsLoading(true);
      try {
        const slots = await getAvailableSlots(selectedDate);
        setAvailableSlots(slots);
      } catch (err) {
        console.error("获取可用时段失败:", err);
        setAvailableSlots([]);
      } finally {
        setIsLoading(false);
      }
    };

    fetchSlots();
  }, [selectedDate, getAvailableSlots]);

  return (
    <form>
      <div className="mb-4">
        <label htmlFor="date" className="block mb-1">选择预订日期</label>
        <input
          type="date"
          id="date"
          {...register("date")}
          className="border rounded px-3 py-2"
        />
      </div>

      <div className="mb-4">
        <label htmlFor="slot" className="block mb-1">选择可用时段</label>
        {isLoading ? (
          <p className="text-sm text-gray-500">加载中...</p>
        ) : (
          <select
            id="slot"
            className="border rounded px-3 py-2 w-full"
            disabled={availableSlots.length === 0}
          >
            {availableSlots.length === 0 ? (
              <option value="" disabled>暂无可用时段</option>
            ) : (
              availableSlots.map(slot => (
                <option key={slot.id} value={slot.id}>
                  {slot.time}
                </option>
              ))
            )}
          </select>
        )}
      </div>

      {/* 其他表单字段与提交按钮 */}
      <button type="submit" className="bg-blue-500 text-white px-4 py-2 rounded">提交预订</button>
    </form>
  );
}

关键说明

  • 类型修正:确保Server Action的类型正确反映异步特性,避免类型报错。
  • 异步触发:通过useEffect监听日期变化,自动触发时段查询,无需手动点击按钮。
  • 用户体验:加载状态和空状态提示让用户清晰了解当前操作进度。

内容的提问来源于stack exchange,提问作者Owain Williams

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 00:38:13