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

React调用fetch删除数据后更新组件状态报map undefined错误

报错根因

你的报错来自这行错误代码:

.then(() => setRecipes(recipeSetter()))

recipeSetter函数没有写返回值,执行后默认返回undefined,这行代码等价于直接把recipes状态设置为undefined,后续组件渲染时对undefined调用.map()方法,就会抛出Cannot read properties of undefined (reading 'map')的错误。

两种正确实现方式

删除数据后更新列表有两种通用方案,根据业务场景选择即可:

方案1:删除成功后重新拉取全量列表

如果列表数据量不大、或者需要保证和服务端数据强一致(比如多用户同时操作同一份数据的场景),可以直接在删除请求成功后重新调用拉取列表的方法。注意recipeSetter内部已经调用了setRecipes,不需要再把它的执行结果传给setRecipes,修正后的删除逻辑代码:

const deleteRecipe = (e, id) => {
  e.preventDefault()
  fetch('/api/recipes/delete', {
    method: 'POST',
    headers: { 'Content-type': 'application/json' },
    body: JSON.stringify({ id }),
  })
  .then(() => recipeSetter()) // 直接调用拉取方法即可,不需要套setRecipes
  .catch(err => console.log('删除失败:', err))
}

方案2:本地过滤删除对应项(性能更优)

如果列表数据量较大,且删除接口返回成功就代表数据确实在服务端删除成功,可以直接在本地过滤掉被删除的项,不需要额外发一次GET请求拉全量数据,减少接口开销:

const deleteRecipe = (e, id) => {
  e.preventDefault()
  fetch('/api/recipes/delete', {
    method: 'POST',
    headers: { 'Content-type': 'application/json' },
    body: JSON.stringify({ id }),
  })
  .then(() => {
    // 基于原有状态过滤掉id匹配的已删除项
    setRecipes(prevRecipes => prevRecipes.filter(recipe => recipe.id !== id))
  })
  .catch(err => console.log('删除失败:', err))
}
额外优化建议
  • 列表渲染时不要用数组索引idx作为key,替换为数据唯一标识recipe.id,否则增删列表项时容易出现组件状态错乱、渲染异常的问题,修正后的列表代码片段:
const recipeList = recipes.map((recipe) => (
  <React.Fragment key={recipe.id}>
    <div className="recipe">
      <span>
        <Link to={'/edit/' + recipe.id}>{recipe.recipe_name}</Link>
      </span>
      <span
        className="delete"
        onClick={(evt) => deleteRecipe(evt, recipe.id)}
      >
        Delete
      </span>
    </div>
  </React.Fragment>
))
  • 所有接口请求建议都加上catch错误捕获,避免请求静默失败用户无感知
  • 可以给删除按钮加临时禁用/loading状态,防止用户重复点击触发多次请求

内容的提问来源于stack exchange,提问作者deadant88

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 23:27:17