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

NextJS SSR实现无页面重载删除图片后刷新数据方案

解决NextJS SSR删除图片后客户端即时移除的问题

问题核心在于你的Dashboard组件是SSR渲染,文件列表files是服务器端一次性获取的静态数据,客户端没有维护状态,所以删除操作后无法触发页面重新渲染。以下是具体修改方案:

步骤1:将Dashboard改为客户端组件并维护文件状态

在Dashboard中添加"use client"指令,用React的useState管理文件列表,让客户端可以动态更新数据:

"use client" // 转为客户端组件
import { getAllFilesFromFolder } from '../utils/fileUtils';
import ImageCard from "../components/imagecard";
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import { useState } from 'react'; // 引入状态管理

const path: any = process.env.FOLDER_PATH;
const initialFiles = getAllFilesFromFolder(path);

export default function Dashboard() {
    // 用useState维护文件列表状态
    const [files, setFiles] = useState(initialFiles);

    // 定义删除回调,接收要删除的图片src
    const handleImageDelete = (deletedSrc: string) => {
        const deletedFileName = deletedSrc.split('/').pop();
        setFiles(prevFiles => prevFiles.filter(file => {
            const fileName = file.split('\\').pop() || file;
            return fileName !== deletedFileName;
        }));
    };

    return (
        <main>
            <ToastContainer
                position="top-right"
                autoClose={5000}
                hideProgressBar={false}
                newestOnTop={false}
                closeOnClick
                rtl={false}
                pauseOnFocusLoss
                draggable
                pauseOnHover
                theme="dark"
            />
            <div className="mt-12 mx-20">
                <div className="grid grid-cols-4 gap-5">
                    {files.map((file) => {
                        const fileName = file.split('\\').pop() || file;
                        const src = `/api/images/${fileName}`;
                        // 改用fileName作为key,避免index导致的渲染异常
                        return <ImageCard key={fileName} src={src} onDelete={handleImageDelete} />;
                    })}
                </div>
            </div>
        </main >
    );
}

步骤2:修改ImageCard组件,接收删除回调并触发更新

更新ImageCard的Props,添加onDelete回调,在删除请求成功后调用它,通知父组件移除对应图片:

"use client"
import { ClipboardIcon, TrashIcon } from "@radix-ui/react-icons";
import { Button, Card, Flex, Inset, Tooltip } from "@radix-ui/themes";
import Image from "next/image";
import { useState } from "react";
import { toast } from "react-toastify";
import DeleteButtonDialog from "./deletebutton";

// 更新Props,添加删除回调
interface ImageCardProps {
    src: string;
    onDelete: (src: string) => void;
}

const ImageCard: React.FC<ImageCardProps> = ({ src, onDelete }) => {
    const [copied, setCopied] = useState(false);

    const copyLinkToClipboard = () => {
        navigator.clipboard.writeText(window.location.host + src)
            .then(() => {
                toast.success('Link erfolgreich kopiert!', {
                    position: "top-right",
                    autoClose: 5000,
                    hideProgressBar: false,
                    closeOnClick: true,
                    pauseOnHover: true,
                    draggable: true,
                    progress: undefined,
                    theme: "dark",
                });
                setCopied(true);
                setTimeout(() => setCopied(false), 2000);
            })
            .catch((error) => {
                console.error('Failed to copy:', error);
            });
    };

    const handleDelete = (confirmed: boolean) => {
        if (confirmed) {
            fetch(src, { method: "DELETE" })
                .then((response) => {
                    if (response.ok) {
                        toast.success('Bild erfolgreich gelöscht!', {
                            position: "top-right",
                            autoClose: 5000,
                            hideProgressBar: false,
                            closeOnClick: true,
                            pauseOnHover: true,
                            draggable: true,
                            progress: undefined,
                            theme: "dark",
                        });
                        // 删除成功后调用父组件的回调,传递当前图片src
                        onDelete(src);
                    } else {
                        console.error("Failed to delete image");
                    }
                })
                .catch((error) => {
                    console.error("Error while deleting image:", error);
                });
        }
    };

    return (
        <main>
            <Card size="2" style={{ maxWidth: 600 }}>
                <Inset clip="padding-box" side="top" pb="current">
                    <Image
                        src={src}
                        width={1000}
                        height={760}
                        className="hidden md:block"
                        alt="Image Card"
                    />
                </Inset>
                <Flex gap="3">
                    <Tooltip content="Link kopieren">
                        <Button onClick={copyLinkToClipboard} variant="soft">
                            <ClipboardIcon width="16" height="16" />
                        </Button>
                    </Tooltip>
                    <DeleteButtonDialog onDelete={handleDelete}></DeleteButtonDialog>
                </Flex>
            </Card>
        </main >
    );
}

export default ImageCard;

关键说明

  • 将Dashboard转为客户端组件并使用useState维护文件列表,让客户端能动态更新数据并触发重新渲染。
  • 通过onDelete回调实现父子组件通信,删除成功后立即通知父组件移除对应条目,无需刷新页面。
  • 把列表项的key从index改为fileName,确保每个列表项的唯一性,避免React渲染异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 22:25:55