如何创建自定义React Hook避免useEffect初始渲染时执行?
实现跳过初始渲染的自定义useEffect Hook
你可以通过创建一个基于useRef的自定义Hook,来标记是否为组件的初始渲染,从而实现仅在依赖项变化时执行副作用逻辑,跳过首次渲染的触发。
自定义Hook实现
import { useState, useEffect, useRef } from 'react'; // 自定义Hook:仅在依赖项更新时执行副作用,跳过初始渲染 export function useEffectUpdate(callback, dependencies) { const isFirstRender = useRef(true); useEffect(() => { // 首次渲染时仅标记状态,不执行回调 if (isFirstRender.current) { isFirstRender.current = false; return; } // 非首次渲染,执行传入的回调,并保留清理函数的返回 return callback(); }, dependencies); }
改造你的Counter组件
将原来的useEffect替换为这个自定义Hook,就能解决localStorage被初始值覆盖的问题:
import React, { useState, useEffect } from 'react'; import { useEffectUpdate } from './useEffectUpdate'; export default function Counter() { const [count, setCount] = useState(0); // 仅在count变化时保存到localStorage,跳过初始渲染 useEffectUpdate(() => { localStorage.setItem('count', count.toString()); }, [count]); useEffect(() => { // 加载已保存的count(初始渲染时执行一次) const savedCount = localStorage.getItem('count'); if (savedCount) { setCount(parseInt(savedCount, 10)); } }, []); return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(prev => prev + 1)}>Increment</button> </div> ); }
逻辑说明
- 初始渲染标记:用
useRef存储isFirstRender状态,它的更新不会触发组件重渲染,比useState更高效。 - 跳过首次执行:首次渲染时,仅将
isFirstRender设为false,不执行副作用回调。 - 依赖变化触发:当依赖项(比如
count)更新时,isFirstRender已经是false,此时执行传入的副作用逻辑。 - 支持清理函数:自定义Hook会返回
callback的返回值,所以如果你的副作用需要清理(比如取消订阅、定时器),可以正常返回清理函数,和原生useEffect的行为一致。
内容的提问来源于stack exchange,提问作者user25148175
相关产品推荐
相关产品推荐

