React Hooks中如何通过子组件点击事件触发父组件重新渲染?——解决子组件删除后父组件重新获取数据失效问题
最优实现:子组件触发删除后父组件重新获取数据
你目前用虚拟计数器触发useEffect的方式虽然能跑通,但确实有点“绕”——它靠一个没有实际业务含义的状态来强制父组件重新请求数据,不仅读起来让人困惑,还可能带来不必要的组件重渲染。下面给你两种更符合React设计理念的最优方案,你可以根据项目规模选择:
方案一:传递刷新回调函数(父子组件简单交互首选)
这是最直接的方案,完全遵循React单向数据流的设计思想:父组件把“刷新数据”的逻辑封装成函数,传递给子组件;子组件完成删除操作后,调用这个函数通知父组件重新拉取数据。
修改后的代码示例
Parent.js
import { useState, useEffect, useCallback } from 'react'; import axios from 'axios'; import Child from './Child'; function Parent() { const [myPetData, setMyPetData] = useState([]); // 初始化对应数据结构 const token = localStorage.getItem("auth-token"); // 抽离数据获取逻辑为独立函数,用useCallback缓存避免不必要的重渲染 const fetchMyPetData = useCallback(() => { axios .get(`${BACK_PORT}/data/mypet`, { headers: { "auth-token": token } }) .then(function (response) { setMyPetData(response?.data); }) .catch(function (error) { console.error("获取宠物数据失败:", error); }); }, [token]); // 组件挂载时首次获取数据 useEffect(() => { fetchMyPetData(); }, [fetchMyPetData]); return ( <div> {/* 把刷新函数传递给子组件 */} <Child onDeleteFinish={fetchMyPetData} /> </div> ); }
Child.js
import axios from 'axios'; function Child({ onDeleteFinish }) { const onDelete = () => { // 先执行删除请求(替换成你的实际删除接口) axios.delete(`${BACK_PORT}/data/mypet/[宠物ID]`, { headers: { "auth-token": localStorage.getItem("auth-token") } }) .then(() => { // 删除成功后,调用父组件传递的刷新函数 onDeleteFinish(); }) .catch(error => { console.error("删除失败:", error); }); }; return ( <button onClick={onDelete}>删除宠物</button> ); }
方案优势
- 代码逻辑清晰,一眼就能看懂“删除后要刷新数据”的关联关系
- 没有冗余的状态变量,避免了无意义的组件重渲染
- 完全符合React单向数据流的设计原则,维护成本低
方案二:使用Context/状态管理库(复杂场景首选)
如果你的项目存在多层组件共享数据、或者多个组件都需要触发数据刷新的场景,用React Context或者状态管理库(如Zustand、Redux)可以避免层层传递回调的麻烦,让数据逻辑更集中。
用React Context实现的示例
PetContext.js
import { createContext, useContext, useState, useEffect, useCallback } from 'react'; import axios from 'axios'; const PetContext = createContext(); export function PetProvider({ children }) { const [myPetData, setMyPetData] = useState([]); const token = localStorage.getItem("auth-token"); const fetchMyPetData = useCallback(() => { axios .get(`${BACK_PORT}/data/mypet`, { headers: { "auth-token": token } }) .then(response => { setMyPetData(response?.data); }) .catch(error => { console.error("获取宠物数据失败:", error); }); }, [token]); useEffect(() => { fetchMyPetData(); }, [fetchMyPetData]); return ( <PetContext.Provider value={{ myPetData, fetchMyPetData }}> {children} </PetContext.Provider> ); } // 自定义Hook,简化Context的调用 export function usePet() { return useContext(PetContext); }
Parent.js
import { usePet } from './PetContext'; import Child from './Child'; function Parent() { const { myPetData } = usePet(); return ( <div> <Child /> </div> ); }
Child.js
import axios from 'axios'; import { usePet } from './PetContext'; function Child() { const { fetchMyPetData } = usePet(); const onDelete = () => { axios.delete(`${BACK_PORT}/data/mypet/[宠物ID]`, { headers: { "auth-token": localStorage.getItem("auth-token") } }) .then(() => { fetchMyPetData(); }) .catch(error => { console.error("删除失败:", error); }); }; return ( <button onClick={onDelete}>删除宠物</button> ); }
方案优势
- 避免了props drilling(多层组件传递回调的麻烦)
- 数据逻辑集中管理,多个组件可以直接调用刷新函数
- 适合中大型项目,扩展性更强
总结
- 若只是简单的父子组件交互,传递回调函数是最直接、最易维护的最优解;
- 若项目存在跨组件数据共享或全局刷新需求,React Context/状态管理库能让代码结构更清晰。
内容的提问来源于stack exchange,提问作者coolps811
相关产品推荐
相关产品推荐

