在使用 React 18 时,大家可能会有这样的困惑,希望在 useEffect 中调用接口查询一些初始化数据,但是发现接口调用了两次
useEffect
钩子在某些情况下确实会执行两次,这可能会让开发者感到困惑。让我们深入分析一下这种情况的原因和解决方法。
为什么 useEffect 会执行两次
useEffect
钩子在某些情况下会执行两次,主要有以下几个原因:
-
严格模式(Strict Mode):
在 React 的严格模式下,某些生命周期方法和钩子会被故意调用两次。这是为了帮助开发者发现潜在的问题,特别是与副作用相关的问题。 -
开发环境:
在开发环境中,React 会进行额外的检查和验证,这可能导致某些钩子被调用多次。 -
组件重新挂载:
如果父组件导致子组件重新挂载,useEffect 也会再次执行。
如何处理这种情况
虽然 useEffect 执行两次通常不会导致严重问题,但如果你希望避免不必要的 API 调用或其他副作用,可以考虑以下方法:
-
使用状态标志:
const [isDataFetched, setIsDataFetched] = useState(false); useEffect(() => { if (!isDataFetched) { getDataList(); setIsDataFetched(true); } }, [isDataFetched]);
-
使用 useRef:
const dataFetchedRef = useRef(false); useEffect(() => { if (dataFetchedRef.current) return; dataFetchedRef.current = true; getDataList(); }, []);
-
移除严格模式:
如果你确定不需要严格模式的额外检查,可以在生产环境中移除它。 -
使用 useCallback:
将getDataList
函数用useCallback
包裹,可以确保它的引用稳定性。
最佳实践
- 在开发过程中保留严格模式,以便及早发现潜在问题。
- 确保你的
getDataList
函数是幂等的,即多次调用不会产生意外的副作用。 - 如果
getDataList
是一个异步操作,考虑使用防抖或节流技术。 - 在生产环境中,这个问题通常不会出现,所以可以主要关注开发环境中的行为。
通过理解这些原因和采取适当的措施,你可以更好地控制 useEffect 的行为,确保你的应用性能优良且没有不必要的副作用。