DOMException: removeChild执行失败,快速响应时map渲染组件报错如何处理?
报错根因
你遇到的这个DOM异常是React列表渲染的典型问题:
- 用map渲染动态列表时没有给每一项添加唯一的
key属性,React无法精准追踪每个节点的增删改操作,当两次渲染间隔极短、前一轮DOM更新还没完成就触发下一轮更新时,就会出现要删除的DOM节点已经不存在的冲突 - 后端响应过快导致tree状态短时间内连续更新,触发多次非必要重渲染,加重了节点操作的冲突概率
修复方案
1. 优先给map列表项添加唯一key
这是成本最低效果最好的修复方式,不要用数组索引作为key,要使用分类数据自带的唯一业务ID:
const getProductsWithTree = () => { if(ifExistAndMayorToZero(tree)) { return ( // 新增key属性,替换category.id为你分类数据里实际的唯一字段,比如categoryId tree.map((category:any) => { return ( <GlobalComponents.ProductSliderAsync key={category.id} filterBrand={false} singleProviderId={vendorId} category={category} hideMore={true} isLoading={isLoadingProducts} brandId={brandId} validateIfIsHasProducts={ifIsHasProducts} {...props} /> ) }) ) } }
2. 对tree的更新做防抖处理
如果加key后还有问题,可以对tree的状态更新加300ms以内的防抖,避免短时间内连续触发重渲染:
// 也可以自己实现防抖逻辑,不用依赖第三方库 import { useDebounce } from 'ahooks' // 防抖处理tree,200ms内的多次更新只会触发最后一次渲染 const debouncedTree = useDebounce(tree, { wait: 200 }) // 渲染时改用debouncedTree判断和遍历即可 const getProductsWithTree = () => { if(ifExistAndMayorToZero(debouncedTree)) { return ( debouncedTree.map((category:any) => { return ( <GlobalComponents.ProductSliderAsync key={category.id} filterBrand={false} singleProviderId={vendorId} category={category} hideMore={true} isLoading={isLoadingProducts} brandId={brandId} validateIfIsHasProducts={ifIsHasProducts} {...props} /> ) }) ) } }
3. 额外排查点
如果以上两步还没解决,检查ProductSliderAsync组件内部有没有直接操作DOM的逻辑,要加上组件卸载判断,组件卸载后禁止再操作DOM,避免操作已经被React移除的节点。
内容的提问来源于stack exchange,提问作者Emocrat3
相关产品推荐
相关产品推荐

