React+Apollo项目中删除用户Mutation提前执行的修复问询
问题描述
基于ReactJS和Apollo Client开发项目,实现deleteUser功能时,删除Mutation能正常运行,但缺少确认Modal环节。需求是:管理员点击删除按钮弹出确认Modal,仅在点击Modal内的“Yes”按钮后执行删除Mutation。
当前存在的问题:
- 点击删除用户按钮时,删除Mutation会先执行,之后才弹出确认Modal
- 点击Modal的“Yes”按钮仅触发数据重新获取(refetch),没有实际执行删除逻辑
解决方案
核心思路是把「触发删除」和「执行删除」拆分:点击删除按钮只弹出确认框,确认后才调用删除Mutation。以下是修改后的完整代码:
import React, { useState } from "react"; import { Table, Button } from "react-bootstrap"; import { useMutation } from "@apollo/client"; import { GET_ALL_USERS } from "../../../gql/query"; import { DELETE_USER } from "../../../gql/mutation"; import ModalEdit from "../Modals/ModalEdit"; import ModalConfirm from "../../Common/Modals/ModalConfirm"; const TableUserInfo = ({ data, variables }) => { const [showEditModal, setShowEditModal] = useState(false); const [showDeleteConfirmModal, setShowDeleteConfirmModal] = useState(false); const [targetUsername, setTargetUsername] = useState(""); const [deleteUser, { error, loading }] = useMutation(DELETE_USER); if (loading) return <p>Loading...</p>; if (error) return <p>Error</p>; if ( !data || !data.getAllUsers || !data.getAllUsers.rows || !data.getAllUsers.rows.length ) { return <p className="text-center"> Tidak ada data tersedia </p>; } // 点击删除按钮:仅弹出确认框,不执行删除 const handleOpenDeleteConfirm = (username) => { setTargetUsername(username); setShowDeleteConfirmModal(true); }; // 确认删除:执行Mutation并更新缓存 const handleConfirmDelete = () => { deleteUser({ variables: { username: targetUsername }, update(cache, { data }) { const { getAllUsers } = cache.readQuery({ query: GET_ALL_USERS, variables, }); cache.writeQuery({ query: GET_ALL_USERS, variables, data: { getAllUsers: { ...getAllUsers, totalItems: getAllUsers.totalItems - 1, rows: getAllUsers.rows.filter(user => user.username !== targetUsername) } } }); }, onError: (error) => { console.log(JSON.stringify(error, null, 2)); }, }); // 执行完删除后关闭Modal setShowDeleteConfirmModal(false); }; return ( <Table responsive> <thead> <tr> <th>No</th> <th>Nama Pengguna</th> <th>Role Akun</th> <th>Email</th> <th>Tanggal Daftar</th> <th>Status Akun</th> <th>Pengaturan</th> </tr> </thead> <tbody> {data.getAllUsers.rows.map((user, index) => ( <tr key={user.username}> <td>{index + 1}</td> <td>{user.full_name}</td> <td>{user.group_id}</td> <td>{user.email}</td> <td>{user.created_dtm}</td> <td>{user.status}</td> <td> {user.status !== "ACTIVE" ? [ <Button key="Aktifkan Akun" className="d-block mb-2 text-white bg-secondary w-100" > Aktifkan Akun </Button>, <Button key="Ganti Role Akun" className="d-block mb-2 btn-block btn-sm w-100" disabled > Ganti Role Akun </Button>, ] : user.group_id === "admin" ? [ <Button key="Ganti Role Akun" variant="outline-success" className="d-block btn-sm mb-2 w-100" > Ganti Role Akun </Button>, ] : [ <Button key="Pilih Role Akun" className="d-block btn-sm mb-2 w-100" > Pilih Role Akun </Button>, ]} <Button key="Edit" variant="outline-primary" onClick={() => { setShowEditModal(true); setTargetUsername(user.username); }} className="d-block btn-block btn-sm mb-2 w-100" disabled={loading} > Edit </Button> <Button key="Hapus" variant="outline-danger" onClick={() => handleOpenDeleteConfirm(user.username)} disabled={loading} className="d-block btn-block btn-sm mb-2 w-100" > Hapus </Button> </td> </tr> ))} </tbody> {/* 编辑Modal */} {showEditModal && ( <ModalEdit show={showEditModal} onClose={() => setShowEditModal(false)} username={targetUsername} /> )} {/* 删除确认Modal */} {showDeleteConfirmModal && ( <ModalConfirm show={showDeleteConfirmModal} onHide={() => setShowDeleteConfirmModal(false)} onConfirm={handleConfirmDelete} userToDelete={targetUsername} /> )} </Table> ); }; export default TableUserInfo;
关键改动说明
- 拆分状态管理:把编辑和删除的Modal状态分开(
showEditModal、showDeleteConfirmModal),避免状态冲突;用targetUsername统一存储当前操作的用户名 - 修改删除触发逻辑:点击「Hapus」按钮时调用
handleOpenDeleteConfirm,仅弹出确认框,不执行删除Mutation - 新增确认执行逻辑:
handleConfirmDelete函数专门处理确认后的删除操作,执行Mutation并更新缓存,完成后关闭Modal - 调整Modal参数传递:给
ModalConfirm传递onConfirm回调,替代原来的handleDelete,确保点击「Yes」时才触发删除
内容的提问来源于stack exchange,提问作者github.arief
相关产品推荐
相关产品推荐

