React中useState设置相同数组值时为何仍触发组件重渲染?
问题根源
React对useState的更新判断用的是浅比较——只看值的内存引用是否一致。你两次调用setOrder传的数组内容完全一样,但它们是两个独立的数组实例(内存地址不一样),所以React会觉得状态变了,触发组件重渲染。
解决办法
给你几种实用的处理方式:
1. 先深比较再更新状态
调用setOrder前,先对比新数组和当前order的内容,只有真的不一样时才更新:
const newOrder = [500, 400, 400, 450]; // 用JSON.stringify做深比较,适合纯基础类型数组 const isSame = JSON.stringify(newOrder) === JSON.stringify(order); if (!isSame) { setOrder(newOrder); }
如果数组里有对象、函数这类复杂类型,JSON.stringify就不好使了,得自己写递归比较逻辑,或者用lodash的isEqual(注意控制依赖体积)
2. 用useEffect精准控制API调用
如果API调用是跟着状态更新走的,把它放进useEffect,用深比较后的结果当依赖:
useEffect(() => { // 这里写你的API调用逻辑 callApi(order); }, [JSON.stringify(order)]); // 只有数组内容变了,才执行API调用
也可以自己写个深比较的Effect钩子:
import { useEffect, useRef } from 'react'; function useDeepCompareEffect(callback, deps) { const prevDepsRef = useRef(); if (!_.isEqual(prevDepsRef.current, deps)) { prevDepsRef.current = deps; } useEffect(callback, [prevDepsRef.current]); } // 用的时候这样写 useDeepCompareEffect(() => { callApi(order); }, [order]);
3. 缓存数组引用
如果这个数组是固定不变的,用useMemo缓存它的引用,这样每次传的都是同一个数组:
const cachedOrder = useMemo(() => [500, 400, 400, 450], []); // 之后调用setOrder就传这个缓存的变量 setOrder(cachedOrder); setOrder(cachedOrder); // 两次引用相同,React不会触发重渲染
4. 函数式更新里做比较
用setOrder的函数式写法,对比当前状态和新状态的内容,相同就返回原状态:
setOrder(prev => { const newOrder = [500, 400, 400, 450]; const isSame = JSON.stringify(prev) === JSON.stringify(newOrder); return isSame ? prev : newOrder; });
这种情况如果内容一致,返回的是原状态的引用,React会直接跳过重渲染。
额外说明
你说别人视频里没这个问题,大概率是他们的场景里,两次setState传的是同一个引用的数组(比如提前缓存好的变量),或者状态是数字、字符串这类基础类型——基础类型的浅比较就是比值,相同值自然不会触发重渲染。
内容的提问来源于stack exchange,提问作者wynnawinner
相关产品推荐
相关产品推荐

