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

调用/pages/api接口时React useTransition的isPending始终为true问题

useTransition的isPending始终为true,无法刷新React Server Component

调用/pages/api/clients的DELETE接口删除MongoDB记录后,useTransition的isPending一直保持true,按钮持续显示"Loading",React Server Component也没能按预期刷新。

错误原因分析

  1. API接口未等待异步操作完成
    服务端的deleteClientById是异步操作(MongoDB的删除方法均为异步),但接口handler直接调用后就返回响应,导致数据库删除还未完成时,前端就触发了router.refresh,此时数据未更新,RSC刷新后状态不一致,进而导致transition无法正常结束。

  2. Fetch请求格式错误
    前端fetch的body直接传递details._id字符串,但Next.js API默认解析JSON格式的请求体,未设置正确的Content-Type头,可能导致后端无法正确获取ID,删除操作失败,间接引发transition异常。

  3. startTransition触发时机存在隐患
    虽然await了fetch,但如果接口提前返回(未等数据库操作完成),此时调用router.refresh获取的仍是旧数据,React无法感知状态更新完成,isPending就会一直停留在true。

修复方案

1. 修复服务端API接口

确保等待数据库删除操作完成后再返回响应:

import type { NextApiRequest, NextApiResponse } from 'next';
import ClientsCollection from '../../db/collections/clients';
import Client from '../../helpers/interfaces/client';

type Data = {
  name: string;
};
const clientsCollection = new ClientsCollection();

export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
  switch (req.method) {
    case 'DELETE': {
      try {
        // 等待异步删除操作完成
        const result = await clientsCollection.deleteClientById(req.body);
        res.status(200).json(result);
      } catch (error) {
        res.status(500).json({ error: '删除操作失败' });
      }
      break;
    }
    default:
      res.status(403).json({ error: '不支持的请求方法' });
  }
}

2. 修正客户端Fetch请求格式

添加正确的请求头,序列化请求体:

'use client'

const DeleteButton = ({ details }) => {
  const [isPending, startTransition] = useTransition();
  const router = useRouter();
  
  const handleDelete = async () => {
    try {
      // 修正fetch请求格式
      await fetch('/api/clients', {
        method: 'DELETE',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(details._id),
      });
      // 确保数据库操作完成后,触发transition刷新RSC
      startTransition(() => {
        router.refresh();
      });
    } catch (error) {
      console.error('删除失败:', error);
      // 可在此添加错误提示,isPending会自动恢复为false
    }
  }

  useEffect(() => {
    console.log('is pending ? ', isPending);
  }, [isPending]);

  return <Button onClick={handleDelete}>{ isPending ? 'Loading' : 'Delete' }</Button>
}

额外注意点

  • 确保clientsCollection.deleteClientById内部正确返回Promise,且正确执行MongoDB删除操作(比如使用deleteOne或findByIdAndDelete并返回结果)。
  • 若router.refresh后RSC仍未刷新,检查RSC的数据获取逻辑是否为动态(如使用async/await从数据库拉取数据,而非静态生成)。

内容的提问来源于stack exchange,提问作者Ondřej Ševčík

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 07:25:31