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

Next.js:如何在前端展示Server Action返回结果及最佳实践

问题:Next.js Server Action返回的数据如何在前端正确展示?

我是Next.js新手,最近尝试使用新的Server Action功能。我创建了一个表单,提交时会触发Server Action从外部API获取图片链接数组,但不知道怎么在前端正确展示返回的结果。我原本想用原生DOM操作更新页面,但感觉不符合Next.js的最佳实践,想找正确的实现方案。

我的相关代码如下:

page.tsx

import Form from "@/components/Form";

export default function Home() {
  return (
    <div className="container mx-auto flex justify-center items-center h-screen">
      <Form />
    </div>
  );
}

form.tsx

"use client";

import { requestImg } from "@/actions/formActions";

export const Form = () => {
  return (
    <form
      className="bg-white p-8 rounded shadow-md"
      action={async (formData) => {
        await requestImg(formData);
      }}
    >
    ... 其他内容(比如输入框和提交按钮) ...
   </form>
  );
};

export default Form;

formActions.ts

"use server";

export const requestImg = async (FormData: FormData) => {
  const link = FormData.get("link");

  const response = await fetch(
    `https://<my API link>/get-all-images/`,
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        link_post: link,
      }),
    }
  );
  const result = await response.json();
  console.log(result);
};

解决方案

方案一:客户端组件用状态管理(推荐)

这是最符合React/Next.js理念的方式:用useState存储图片数组,通过表单action函数接收Server Action返回的结果,再更新状态驱动页面渲染。

第一步:修改Server Action,返回结果

先修改formActions.ts,把获取到的图片数组return出去,同时增加错误处理:

"use server";

export const requestImg = async (formData: FormData) => {
  const link = formData.get("link");

  const response = await fetch(
    `https://<my API link>/get-all-images/`,
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        link_post: link,
      }),
    }
  );

  // 处理API请求失败的情况
  if (!response.ok) {
    throw new Error("获取图片失败,请稍后重试");
  }

  const result = await response.json();
  return result; // 返回图片链接数组
};

第二步:修改客户端表单组件,管理状态并渲染图片

更新form.tsx,加入状态管理和图片渲染逻辑:

"use client";

import { useState } from "react";
import { requestImg } from "@/actions/formActions";

export const Form = () => {
  const [images, setImages] = useState<string[]>([]);
  const [isLoading, setIsLoading] = useState(false);

  return (
    <div className="flex flex-col items-center gap-6">
      <form
        className="bg-white p-8 rounded shadow-md"
        action={async (formData) => {
          setIsLoading(true);
          try {
            // 接收Server Action返回的图片数组
            const imageUrls = await requestImg(formData);
            setImages(imageUrls);
          } catch (err) {
            alert(err instanceof Error ? err.message : "未知错误");
          } finally {
            setIsLoading(false);
          }
        }}
      >
        {/* 表单输入区域 */}
        <input
          type="text"
          name="link"
          placeholder="输入目标链接"
          className="w-full mb-4 p-2 border border-gray-300 rounded"
          required
        />
        <button
          type="submit"
          disabled={isLoading}
          className="w-full p-2 bg-blue-500 text-white rounded hover:bg-blue-600 disabled:bg-gray-400"
        >
          {isLoading ? "加载中..." : "获取图片"}
        </button>
      </form>

      {/* 图片展示区域 */}
      {isLoading && <p className="text-gray-600">正在加载图片...</p>}
      {images.length > 0 && (
        <div className="mt-4 grid grid-cols-3 gap-4">
          {images.map((url, index) => (
            <img
              key={index}
              src={url}
              alt={`图片${index + 1}`}
              className="w-full h-auto rounded shadow"
            />
          ))}
        </div>
      )}
    </div>
  );
};

export default Form;

方案二:Server Action重定向+服务器组件传递数据

如果需要在服务器组件中处理并渲染结果,可以通过搜索参数传递数据(适合数据量不大的场景):

第一步:修改Server Action,重定向并携带数据

更新formActions.ts:

"use server";
import { redirect } from "next/navigation";

export const requestImg = async (formData: FormData) => {
  const link = formData.get("link");

  const response = await fetch(
    `https://<my API link>/get-all-images/`,
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        link_post: link,
      }),
    }
  );

  if (!response.ok) {
    throw new Error("获取图片失败,请稍后重试");
  }

  const result = await response.json();
  // 将图片数组转为编码后的字符串,通过搜索参数传递
  const encodedImages = encodeURIComponent(JSON.stringify(result));
  redirect(`/?images=${encodedImages}`);
};

第二步:修改服务器组件,解析参数并渲染图片

更新page.tsx:

import Form from "@/components/Form";

export default function Home({ searchParams }: { searchParams: { images?: string } }) {
  let images: string[] = [];
  if (searchParams.images) {
    try {
      images = JSON.parse(decodeURIComponent(searchParams.images));
    } catch (err) {
      console.error("解析图片数据失败:", err);
    }
  }

  return (
    <div className="container mx-auto flex flex-col justify-center items-center h-screen gap-8">
      <Form />
      {/* 展示图片 */}
      {images.length > 0 && (
        <div className="grid grid-cols-3 gap-4">
          {images.map((url, index) => (
            <img key={index} src={url} alt={`图片${index+1}`} className="rounded shadow" />
          ))}
        </div>
      )}
    </div>
  );
}

最佳实践总结

  • 优先选择方案一:客户端状态管理更直观,符合React状态驱动渲染的核心思想,避免原生DOM操作带来的维护问题。
  • 方案二适合需要在服务器组件中处理结果的场景,但注意搜索参数有长度限制,数据量较大时不适用。
  • 始终在Server Action中处理错误并抛出,方便客户端捕获并给用户清晰的反馈。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 15:28:17