为何_.remove会修改原数组?useState数组同步变更问题
问题原因与解决方案
为什么原数组会被同步修改?
- JavaScript里数组属于引用类型,
const newArray = backendArray;这行代码并没有创建新的数组,只是让newArray和backendArray指向内存中同一个数组对象。两个变量共享同一个引用,操作其中一个就等于直接操作原数组。 - 另外,
_.remove方法的特性是直接修改调用它的原数组,它会从目标数组中移除符合条件的元素,同时返回被移除的元素。你用它操作newArray,本质上就是在修改backendArray指向的那个数组。
怎么解决?
你需要先创建原数组的独立副本,再对副本进行操作,切断和原数组的引用关联:
1. 浅拷贝(适用于数组元素是基本类型或不需要修改嵌套对象的场景)
可以用扩展运算符或Array.from()创建副本:
const [backendArray, setBackendArray] = useState([{/* some values */}]) useEffect(() => { // 创建原数组的浅拷贝副本 const newArray = [...backendArray]; // 对副本执行移除操作 const arrayForPurpose1 = _.remove(newArray, n => n.value != null); // 此时backendArray不会被修改,newArray是移除后的结果 }, [backendArray]);
2. 深拷贝(适用于数组元素是嵌套对象,需要完全切断所有引用的场景)
如果数组里的元素是嵌套对象,浅拷贝只会复制对象的引用,修改副本里的对象还是会影响原数组。这时可以用lodash的_.cloneDeep做深拷贝:
const [backendArray, setBackendArray] = useState([{/* some values */}]) useEffect(() => { // 创建原数组的深拷贝副本 const newArray = _.cloneDeep(backendArray); const arrayForPurpose1 = _.remove(newArray, n => n.value != null); }, [backendArray]);
更简洁的替代方案
如果你的需求只是筛选出value != null的元素,完全可以用_.filter替代_.remove——它不会修改原数组,直接返回符合条件的新数组,代码更安全简洁:
const [backendArray, setBackendArray] = useState([{/* some values */}]) useEffect(() => { const arrayForPurpose1 = _.filter(backendArray, n => n.value != null); // 原backendArray完全不受影响 }, [backendArray]);
内容的提问来源于stack exchange,提问作者Joseph Walsh
相关产品推荐
相关产品推荐

