删除数组元素时useCallback失效,选中图片样式丢失问题
问题描述
点击图标删除图片时,和待删图片同属一个数组的已选中图片会丢失选中样式,尝试用useCallback解决但无效。
原代码
import uuid from "react-uuid"; const [image, setImage] = useState<Blob[]>([]); const [selectedImage, setSelectedImage] = useState<Blob | null>(null); const deleteImage = (singleImage: Blob) => { const filteredList = Array.from(image).filter(function (img) { return img !== singleImage; }); setImage(filteredList); }; const memoCall = useCallback((img: Blob) => { console.log("memoCall"); if (selectedImage === img) { setSelectedImage(null); } else { setSelectedImage(img); } }, [selectedImage]); return ( {image?.length > 0 && image.map((img, index) => selectedImage === img ? ( <div className="w-full h-[300px] relative border-red-500 border-4" key={uuid()} onClick={() => memoCall(img)} >...</div> ) : ( <div className="w-full h-[300px] relative" key={uuid()} onClick={() => memoCall(img)} >...</div> ) ) } );
问题根源
- key值不稳定:用
uuid()作为元素key,每次组件渲染都会生成新的key,React会把每个图片元素当成全新组件重新挂载,之前的选中状态关联直接失效,样式自然丢失。 - 删除逻辑未处理选中状态:删除图片时,如果选中的是其他图片,虽然
selectedImage的引用还在,但组件重新挂载后,React无法匹配到对应元素,导致样式不生效;如果删除的是选中图片,也没有主动清空选中状态。 - useCallback无法解决核心问题:当前
memoCall的依赖只有selectedImage,但函数的稳定性无法抵消key值不稳定带来的组件重新挂载问题。
解决方案
1. 改用稳定的key值
不要用动态生成的uuid(),可以给每个图片对象添加唯一标识(比如上传时生成id,存成{id: string, blob: Blob}的结构),或者在图片顺序固定的场景下用数组index。
2. 完善删除逻辑
删除图片时,检查当前选中的图片是否在被删除的列表里,如果是,主动清空选中状态;如果是其他图片,确保选中状态能正确关联。
修正后的代码
import uuid from "react-uuid"; // 给图片添加唯一标识,避免依赖Blob引用判断 interface ImageItem { id: string; blob: Blob; } const [images, setImages] = useState<ImageItem[]>([]); const [selectedImageId, setSelectedImageId] = useState<string | null>(null); // 上传图片时,为每个图片生成唯一id const handleImageUpload = (newBlobs: Blob[]) => { const newImages = newBlobs.map(blob => ({ id: uuid(), blob })); setImages(prev => [...prev, ...newImages]); }; const deleteImage = (targetId: string) => { const filteredList = images.filter(img => img.id !== targetId); // 如果删除的是当前选中的图片,清空选中状态 if (selectedImageId === targetId) { setSelectedImageId(null); } setImages(filteredList); }; const toggleSelectImage = useCallback((imageId: string) => { setSelectedImageId(prev => prev === imageId ? null : imageId); }, []); return ( {images.length > 0 && images.map((img) => ( <div className={`w-full h-[300px] relative ${selectedImageId === img.id ? 'border-red-500 border-4' : ''}`} key={img.id} onClick={() => toggleSelectImage(img.id)} > {/* 图片内容 */} <button onClick={(e) => { e.stopPropagation(); // 阻止触发选中事件 deleteImage(img.id); }}>删除</button> </div> )) } );
关键说明
- 用
id而非Blob引用做选中判断,避免Blob引用变化导致的匹配失败 - 稳定的
img.id作为key,确保React能正确追踪组件状态 - 删除时主动处理选中状态,避免残留无效的选中标识
内容的提问来源于stack exchange,提问作者Captai-N
相关产品推荐
相关产品推荐

