React食谱应用:执行DELETE请求后如何更新数据状态
解决React食谱应用删除后数据不自动更新的问题
嘿,我明白你遇到的问题了——删除食谱后必须刷新页面才能看到最新列表,确实有点影响体验。咱们来一步步解决这个问题,核心思路就是在DELETE请求成功后,主动触发数据状态的更新,不用等页面刷新。
问题根源
你的useFetch钩子应该是在组件挂载时只执行了一次数据请求,删除操作完成后并没有通知它重新获取数据,所以页面上的列表还是旧的。下面给你几个实用的解决方案,你可以根据自己的代码结构选一个最适合的:
方案1:让自定义useFetch支持手动重新请求
首先检查你的useFetch实现,如果它还没有暴露重新请求的方法,咱们给它加一个refetch函数,同时让它能监听一个刷新触发键。
修改useFetch钩子:
import { useState, useEffect } from 'react'; function useFetch(url, refreshKey = 0) { const [data, setData] = useState(null); const [error, setError] = useState(null); const [isPending, setIsPending] = useState(true); // 封装请求逻辑 const fetchData = async () => { setIsPending(true); try { const res = await fetch(url); if (!res.ok) throw new Error(`请求失败:${res.status}`); const json = await res.json(); setData(json); setError(null); } catch (err) { setError(err.message); setData(null); } finally { setIsPending(false); } }; // 依赖变化时自动请求 useEffect(() => { fetchData(); }, [url, refreshKey]); // 暴露手动重新请求的方法 const refetch = fetchData; return { data, error, isPending, refetch }; } export default useFetch;
在删除函数中调用refetch:
如果删除组件和列表页在同一个上下文里,或者能拿到refetch方法,直接在DELETE成功后调用它:
function handleDelete() { fetch(url_recipes + id, { method: 'DELETE' }) .then(response => response.text()) .then(json => { console.log("Deleted!", json); // 调用refetch重新获取数据 refetch(); navigate("/"); }) .catch(error => console.log('Error message: ', error)); }
方案2:通过状态触发列表页重新请求
如果不想修改useFetch,可以在列表页加一个状态变量,用来触发useFetch的重新执行:
列表页代码:
import { useState } from 'react'; import useFetch from './useFetch'; function RecipeList() { // 用一个计数器作为刷新触发键 const [refreshTrigger, setRefreshTrigger] = useState(0); const { data: recipes, error, isPending } = useFetch(url_recipes, refreshTrigger); // 给子组件传递刷新函数 const handleRecipeDeleted = () => { // 更新计数器,触发useFetch重新请求 setRefreshTrigger(prev => prev + 1); }; return ( <div> {isPending && <div>加载中...</div>} {error && <div>出错了:{error}</div>} {recipes && recipes.map(recipe => ( <RecipeItem key={recipe.id} recipe={recipe} onDelete={handleRecipeDeleted} /> ))} </div> ); }
删除组件中调用刷新函数:
function RecipeItem({ recipe, onDelete }) { const navigate = useNavigate(); function handleDelete() { fetch(url_recipes + recipe.id, { method: 'DELETE' }) .then(response => response.text()) .then(json => { console.log("Deleted!", json); // 通知列表页刷新数据 onDelete(); navigate("/"); }) .catch(error => console.log('Error message: ', error)); } return ( <div> <h3>{recipe.title}</h3> <button onClick={handleDelete}>删除食谱</button> </div> ); }
方案3:本地直接更新状态(无需重新请求API)
如果你的食谱数据是存在本地状态里的,删除成功后可以直接过滤掉已删除的条目,这样不用再发一次API请求,体验更流畅:
import { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; function RecipeList() { const [recipes, setRecipes] = useState(null); const [error, setError] = useState(null); const [isPending, setIsPending] = useState(true); const navigate = useNavigate(); // 初始加载数据 useEffect(() => { fetch(url_recipes) .then(res => { if (!res.ok) throw new Error('加载失败'); return res.json(); }) .then(data => { setRecipes(data); setIsPending(false); setError(null); }) .catch(err => { setError(err.message); setIsPending(false); }); }, []); // 删除并更新本地状态 const handleDelete = (id) => { fetch(url_recipes + id, { method: 'DELETE' }) .then(response => response.text()) .then(json => { console.log("Deleted!", json); // 过滤掉已删除的食谱 setRecipes(prev => prev.filter(recipe => recipe.id !== id)); navigate("/"); }) .catch(error => console.log('Error message: ', error)); }; return ( <div> {isPending && <div>加载中...</div>} {error && <div>出错了:{error}</div>} {recipes && recipes.map(recipe => ( <div key={recipe.id}> <h3>{recipe.title}</h3> <button onClick={() => handleDelete(recipe.id)}>删除食谱</button> </div> ))} </div> ); }
这三个方案里,我个人推荐方案1或3:方案1适合用自定义钩子管理数据的场景,扩展性强;方案3适合追求性能的场景,减少不必要的API请求。
内容的提问来源于stack exchange,提问作者random_user1234
相关产品推荐
相关产品推荐

