React useEffect仅首次删除触发,AgGridReact无法重复更新
问题分析与解决方案
问题根源
你的代码中,deleteHandler被用作AgGrid的cellRenderer回调,但AgGrid会缓存cellRenderer组件,导致首次渲染时的deleteHandler被一直复用。这个旧的deleteHandler捕获了初始的productDeleted=false状态,后续每次删除时调用setProductDeleted(!productDeleted),本质是把状态从true再次设置为true(因为闭包中的productDeleted始终是初始的false)——状态没有发生实际变化,所以useEffect不会触发,网格也就无法更新。
同时你看到的console.log(productDeleted)始终为false,是因为React状态更新是异步的,set操作后的console.log读取的仍是更新前的旧值。
解决方案
方案1:使用函数式更新切换状态
通过函数式更新获取最新状态,避免闭包捕获旧值的问题,确保每次删除都能触发状态变化:
const deleteHandler = (productId) => { if ( window.confirm( "Voulez-vous vraiment supprimer ce produit ?\nCette action est irreversible." ) ) { deleteProduct(productId) .then(data => { if (data === "Product deleted") { // 使用函数式更新,基于最新状态取反 setProductDeleted(prevState => !prevState); window.alert("Produit supprimé !"); } else { console.error(data); } }) .catch(err => console.error(err)) } };
方案2:删除成功后直接更新数据(推荐)
去掉productDeleted状态,删除成功后直接调用接口刷新数据,逻辑更直观,也能彻底规避闭包问题:
const deleteHandler = (productId) => { if ( window.confirm( "Voulez-vous vraiment supprimer ce produit ?\nCette action est irreversible." ) ) { deleteProduct(productId) .then(data => { if (data === "Product deleted") { const abctrl = new AbortController(); // 删除成功后直接重新获取数据并更新网格 fetchProducts(abctrl) .then(rawData => formatData(rawData)) .then(formattedData => setRowData(formattedData)) .catch(er => { const errorMessage = er.response.data.message ? er.response.data.message : er.response.data; redirectionFromAdminPages(errorMessage, reduxDispatch); }); window.alert("Produit supprimé !"); } else { console.error(data); } }) .catch(err => console.error(err)) } };
同时修改useEffect的依赖,去掉productDeleted:
useEffect(() => { console.log("useEffect...") const abctrl = new AbortController(); fetchProducts(abctrl) .then((data) => formatData(data)) .then((res) => setRowData(res)) .catch((er) => { const errorMessage = er.response.data.message ? er.response.data.message : er.response.data; redirectionFromAdminPages(errorMessage, reduxDispatch); }); return () => abctrl.abort(); }, [fetchProducts, reduxDispatch]);
方案3:确保cellRenderer获取最新的deleteHandler
通过AgGrid的cellRendererParams传递最新的回调函数,配合useCallback稳定函数引用:
- 用
useCallback包裹deleteHandler:
import { useCallback } from "react"; // ... const deleteHandler = useCallback((productId) => { if ( window.confirm( "Voulez-vous vraiment supprimer ce produit ?\nCette action est irreversible." ) ) { deleteProduct(productId) .then(data => { if (data === "Product deleted") { setProductDeleted(prev => !prev); window.alert("Produit supprimé !"); } else { console.error(data); } }) .catch(err => console.error(err)) } }, [deleteProduct]);
- 修改列定义,传递回调参数:
// 修改editOrDelete列的配置 { field: "editOrDelete", headerName: "Modifier / Supprimer", width: 150, filter: false, cellRenderer: editOrDeleteBtn, cellRendererParams: { deleteHandler: deleteHandler } }
- 更新cellRenderer使用传递的回调:
const editOrDeleteBtn = (params) => { return ( <> <LinkContainer to={`/admin/modifier-produit/${params.value}`}> <Button className="btn-sm"> <i className="bi bi-pencil-square"></i> </Button> </LinkContainer> {" / "} <Button className="btn-sm" variant="danger" onClick={() => params.deleteHandler(params.value)} > <i className="bi bi-x-circle"></i> </Button> </> ); };
内容的提问来源于stack exchange,提问作者Lazare Boddaert
相关产品推荐
相关产品推荐

