React/Next.js中作品激活状态更新后页面刷新失效问题求助
问题分析与修复方案
你遇到的问题核心是数据库中的Brainstorm状态并没有真正被更新,所以页面刷新后会回到初始值。结合你的代码来看,主要有两个关键问题:API路由的更新逻辑错误,以及前端组件的调用逻辑存在缺陷。
1. 修复API路由的核心错误
你的API路由在更新Brainstorm时,错误地使用了用户ID作为查询条件,而不是目标Brainstorm的ID。这会导致你试图更新一条不存在的Brainstorm记录(因为Brainstorm的ID和用户ID是完全不同的字段),数据库操作实际上没有生效。
修改后的API路由代码:
import { NextApiRequest, NextApiResponse } from "next"; import { decryptCookie } from "../../../lib/cookie"; import { prisma } from "../../../lib/prisma"; interface User { email: string; issuer: string; } export default async (req: NextApiRequest, res: NextApiResponse) => { if (req.method !== "PUT") return res.status(405).end(); // 修复end()调用的语法错误 try { const userFromCookie = await decryptCookie(req.cookies.auth); if (!userFromCookie.email) { throw new Error("Cannot find user. Unable to proceed with update."); } const userEmail = userFromCookie.email; // 从请求体中获取要更新的active状态和brainstormId const { active, brainstormId } = JSON.parse(req.body); // 先校验用户权限:确保当前用户拥有该Brainstorm const user = await prisma.user.findUnique({ where: { email: userEmail } }); const targetBrainstorm = await prisma.brainstorm.findFirst({ where: { id: brainstormId, userId: user.id } }); if (!targetBrainstorm) { return res.status(403).json({ message: "You don't have permission to update this brainstorm" }); } // 更新指定的Brainstorm记录(使用brainstormId作为查询条件) const updatedBrainstorm = await prisma.brainstorm.update({ data: { active }, where: { id: brainstormId }, }); res.status(200).json({ response: updatedBrainstorm }); // 用200表示更新成功,201用于创建资源 } catch (error) { console.error(error); return res.status(500).json({ message: error.message }); // 返回JSON格式错误信息,方便前端处理 } };
关键修改点:
- 从请求体接收
brainstormId,明确要更新的目标Brainstorm - 更新逻辑使用
brainstormId而非用户ID作为查询条件 - 增加权限校验,确保用户只能修改自己创建的Brainstorm
- 修正状态码使用(200对应更新成功)和语法错误
- 优化错误处理,返回标准化的JSON错误信息
2. 修复前端组件的调用逻辑
你的前端组件存在两个问题:一是没有传递brainstormId给API,二是setState的异步特性导致传递给API的active值是旧的,同时缺少API调用失败的回滚逻辑。
修改后的组件核心代码:
import React, { useState } from "react"; import Switch from "react-switch"; import { Container, BrainstormInfo, BrainstormTitle, Active, Group, StormPieces, } from "./styles"; import { Brainstorm } from "../../pages/user-dashboard"; import useFormatDate from "../../hooks/useFormatDate"; interface Props { brainstormData: Brainstorm; } const UserBrainstormCard: React.FC<Props> = ({ brainstormData }) => { if (!brainstormData) return <h1>Loading...</h1>; const [active, setActive] = useState(brainstormData.active); const [isUpdating, setIsUpdating] = useState(false); // 添加加载状态 const formatedDate = useFormatDate( (brainstormData.createdAt as unknown) as string ); async function handleActiveness() { if (isUpdating) return; // 防止重复点击 const newActiveState = !active; setIsUpdating(true); setActive(newActiveState); // 乐观更新UI try { const response = await fetch("/api/brainstorm/update", { method: "PUT", headers: { "Content-Type": "application/json", // 必须设置该头,否则后端无法解析JSON }, body: JSON.stringify({ active: newActiveState, brainstormId: brainstormData.id // 传递目标Brainstorm的ID }), }); if (!response.ok) { throw new Error("Failed to update brainstorm status"); } const data = await response.json(); setActive(data.response.active); // 用数据库返回的状态同步UI } catch (error) { console.error(error); setActive(active); // API调用失败,回滚UI状态 alert("Failed to update status, please try again"); } finally { setIsUpdating(false); // 结束加载状态 } } return ( <Container> <BrainstormInfo> <p>Brainstorm</p> <p>{formatedDate}</p> </BrainstormInfo> <BrainstormTitle> <h3>{brainstormData.title}</h3> </BrainstormTitle> <Active> <Group> <p>Active:</p> <Switch offHandleColor="#eee" onHandleColor="#eee" draggable={false} onChange={handleActiveness} checked={active} checkedIcon={false} uncheckedIcon={false} height={15} width={30} handleDiameter={20} offColor="#f13030" onColor="#2dea8f" disabled={isUpdating} // 加载时禁用按钮 /> </Group> <StormPieces> <p> {brainstormData.stormPieces.length} Stormpieces </p> </StormPieces> </Active> </Container> ); }; export default UserBrainstormCard;
关键修改点:
- 提前计算
newActiveState,避免setState异步导致的旧值问题 - 添加
Content-Type请求头,确保后端正确解析请求体 - 传递
brainstormId给API,明确更新目标 - 增加加载状态和重复点击拦截,优化用户体验
- 添加错误回滚逻辑:API调用失败时恢复UI状态
- 移除未使用的
produce依赖
3. 额外优化建议
- 父组件可以在子组件更新状态后,重新拉取Brainstorm列表,确保所有子组件状态同步
- 考虑使用React Query或SWR这类状态管理库,自动处理服务器状态的缓存和重新验证,减少手动同步的工作量
- 可以将API调用逻辑封装成自定义hooks,提高代码复用性
内容的提问来源于stack exchange,提问作者gabriel_tiso
相关产品推荐
相关产品推荐

