You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 18:43:10