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
相关产品推荐
相关产品推荐

