React useEffect依赖项未发生变化时仍触发执行的问题
问题场景
现有如下React组件代码:
import React, { useState, useEffect } from 'react'; import { HousesType } from '@src/store'; export const Home = () => { const [houses, setHouses] = useState<HousesType[]>([]); useEffect(() => { console.log('Should it fire if properties has no length?'); }, [houses.length]) return <h1>Testing</h1> }
实际运行时出现不符合预期的现象:houses数组初始长度为0,依赖项houses.length从组件初始化开始没有发生任何变更,组件首次渲染时依然触发了effect内的控制台日志打印。
原因解释
这是React useEffect Hook的既定运行逻辑,不属于异常:
- useEffect的执行时机分两类:组件首次挂载完成后的初始执行、组件更新阶段依赖项变更触发的重复执行
- 依赖数组的作用仅为控制更新阶段是否触发effect重执行:更新渲染完成后,React会对依赖数组内的每一项做浅比较,只要有任意一项和上一轮渲染的值不同,才会重跑effect
- 首次挂载阶段的effect执行不受依赖数组约束,无论依赖项初始值是什么、有没有变化,组件第一次渲染完成后都会执行一次传入useEffect的回调,这就是初始状态下日志被打印的根本原因。
跳过首次执行的实现方案
如果需要仅在houses.length后续真正发生变更时才执行回调、跳过首次挂载的默认执行,可以通过useRef存储挂载标记做判断:
import React, { useState, useEffect, useRef } from 'react'; import { HousesType } from '@src/store'; export const Home = () => { const [houses, setHouses] = useState<HousesType[]>([]); // 存储首次挂载标记 const firstMountRef = useRef(true); useEffect(() => { // 首次挂载时标记为false,直接返回不执行后续逻辑 if (firstMountRef.current) { firstMountRef.current = false; return; } console.log('仅当houses.length发生变化时触发'); }, [houses.length]) return <h1>Testing</h1> }
内容的提问来源于stack exchange,提问作者Álvaro
相关产品推荐
相关产品推荐

