useEffect 依赖数组判断机制
一句话核心结论#
React 对依赖数组里的每一项,都做 「全等比较(===)」,只要有任意一项变了,effect 就重新执行。
1. 底层判断规则#
每次组件渲染,React 都会做这 3 步:
- 记录上一次的依赖数组
[a, b, c] - 拿到本次新的依赖数组
[a, b, c] - 逐项进行
===比较- 全部相等 → 不执行 effect
- 任意一个不等 → 执行 effect
关键:是「全等比较」,不是「值相等」#
// 基本类型:值相同 → === 相等 → 判定不变
1 === 1 → true
'abc' === 'abc' → true
// 引用类型:地址相同 → === 相等
// 地址不同 → 即使内容一样,也判定变化!
{} === {} → false
[] === [] → false
()=>{} === ()=>{} → falsejs2. 不同数据类型的判断结果#
① 基本类型(数字、字符串、布尔、null、undefined)#
直接比较值,值不变 → 判定不变
// 只会在 count 真正变化时执行
useEffect(() => {
console.log(count);
}, [count]); js② 引用类型(对象、数组、函数)#
比较内存地址,地址变了 → 判定变化 这是 90% 的 bug 来源!
// 每次渲染都创建新对象 → 地址变 → effect 每次都执行!
useEffect(() => {
console.log('我每次渲染都跑!');
}, [{ name: 'react' }]);
// 每次渲染都创建新数组 → effect 每次执行
useEffect(() => {
console.log('我每次渲染都跑!');
}, [[1,2,3]]); js3. 最容易踩坑的 3 个场景#
坑 1:直接在依赖里写对象/数组#
function App() {
const [count, setCount] = useState(0);
// ❌ 错误:每次渲染都是新对象,effect 无限执行
useEffect(() => {
console.log('执行');
}, [{ id: 1 }]);
}js解决方案:用 useMemo 缓存对象/数组
const obj = useMemo(() => ({ id: 1 }), []);
useEffect(() => {
console.log('执行');
}, [obj]); // ✅ 地址不变js坑 2:依赖里写函数(每次渲染都是新函数)#
// ❌ 错误
useEffect(() => {
fetchData();
}, [fetchData]); js解决方案:用 useCallback 缓存函数
const fetchData = useCallback(() => { ... }, []);
useEffect(() => {
fetchData();
}, [fetchData]); // ✅ 地址不变js坑 3:空依赖数组 []#
所有项都不变 → 只在组件挂载执行一次,卸载清理一次
4. 完整执行流程图#
- 组件初次渲染 → 执行 effect
- 组件更新 → 生成新依赖数组
- React 逐项
===对比新旧依赖- 全相等 → 不执行
- 有一个不等 → 先执行清理函数 → 再执行新 effect
总结#
- useEffect 依赖判断用
===全等比较 - 基本类型比数值,引用类型比内存地址
- 对象/数组/函数必须用
useMemo / useCallback缓存,否则会重复执行 - 空依赖
[]= 只执行一次