React版本:所有
重现步骤
- 声明一个状态变量,类型为数组,例如:
useState([1, 2, 3]);
- 在依赖数组中添加一个包含声明的状态变量的useEffect。
- 使用相同的值更新状态变量。
这种情况可能发生是因为,如果在设置状态值后使用'=='检查状态值,那么对于数组的比较总是返回false,从而触发useEffect。
[1, 2, 3] == [1, 2, 3] is false:
"This condition will always return 'false' since JavaScript compares objects by reference, not value."
链接到代码示例:
const [arrVar, setArrVar] = useState([]);
useEffect(() => {
console.log("triggered");
console.log(arrVar);
}, [arrVar])
//Click the button twice.
return (
<button onClick={ (e) => {setArrVar([1, 2, 3])} }>update state</button>
);
当前行为
即使在更新时依赖数组中的数组元素没有改变,useEffect也会被触发。
预期行为
它不应该被触发。
4条答案
按热度按时间pes8fvy91#
这是预期的行为。React遍历旧的和新的依赖数组,并进行“浅等”比较。换句话说,
if (oldDeps[i] !== newDeps[i]) runCallback()
。你提供了一个新的数组引用,并将其包含在依赖数组中。因此,你改变了deps数组的内容,所以它会运行effect回调。这并不重要那个数组的内容是否相同或不同——重要的是deps数组内部的值和引用。
py49o6xq2#
这个条件将始终返回'false',因为JavaScript是通过引用而不是值来比较对象的。
你已经回答了自己。如果比较返回false,无论数组是否包含相同的数据,都应该重新渲染组件,因为在依赖数组中找到的值不相等。
yxyvkwin3#
感谢你的回复。我看到这是预期的行为,它的表现方式符合我的猜测。但这是期望的行为吗?难道useEffect的依赖数组不是用来检测变化并执行一些代码的吗?在这一点上,我认为每次在设置新的状态数据为数组之前,我需要做的就是使用for循环将其与之前的值进行比较。这个操作对我来说没有问题。但是想象一下,每个React用户都在他们的代码中使用这个比较函数。这对“React”来说不是一个期望的状态吗?如果useEffect的依赖数组比较函数通过JavaScript的for循环或其他方式检查引用而不是值的数组和其他对象,而不是使用“===”,那么整体上会更干净的代码吗?或者更新设置状态函数,我指的是useState()返回的第二个元素,如果值相同,则不更新状态?这只会在那些想要保持相同值但改变引用的人身上出现问题,如果有的话。
omqzjyyz4#
如果要在上面的例子中不触发
useEffect
,需要将依赖数组指定为arrVar
,而不是[arrVar]
。否则,您会比较数组(从此渲染器获取的arrVar
与从先前渲染器获取的arrVar
),这将始终是false
,从而触发useEffect
。将
arrVar
作为依赖数组传递将使 React 比较arrVar
的内容。或者执行
[...arrVar]
。这也可以工作,但请不要在实际代码中这样做,谢谢 :)