useEffectAfterMount
Runs an effect only after the component has mounted, skipping the very first
render. It behaves like useEffect, except the callback is never invoked on
initial mount — only on subsequent updates to the given dependencies.
When to use it
- Reacting to prop/state changes without re-running logic on first render.
- Avoiding duplicate work when an effect's initial run is already handled elsewhere (e.g. during data fetching on mount).
- Logging or syncing side effects that should only fire on genuine updates.
Demo
Click the button a few times and watch the console — the effect only logs on updates, never for the initial render.
Loading demo…
Signature
function useEffectAfterMount(fn: () => void, deps?: unknown[]): void;
| Parameter | Type | Description |
|---|---|---|
fn | () => void | The callback to run after mount, whenever deps change. |
deps | unknown[] | Dependency array. Defaults to [] (fn runs once per dependency change). |
Returns: void
Usage notes
- The callback is skipped entirely on the first render — it only fires on subsequent re-renders triggered by a dependency change.
- Useful for avoiding the common "run once on mount, then only on updates"
pattern that plain
useEffectdoesn't support out of the box.
Hook source
View useEffectAfterMount source
useEffectAfterMount sourceuse-effect-after-mount.ts
import { useEffect, useRef } from "react";
/**
* A custom React hook that triggers a callback function only after the component has mounted
* and whenever the specified dependencies change.
*
* This hook is useful in cases where you want to skip the effect on the initial render and
* only trigger it on subsequent renders when dependencies change.
*
* @param {() => void} fn - The callback function to be executed after the component mounts and dependencies change.
* @param {unknown[]} [deps=[]] - An array of dependencies that the effect depends on. When these dependencies change,
* the callback function will be triggered. If not provided, defaults to an empty array.
*
* @example
* ```typescript
* useEffectAfterMount(() => {
* console.log("This will only log on updates, not on the initial render");
* }, [someDependency]);
* ```
*/
export const useEffectAfterMount = (fn: () => void, deps: unknown[] = []) => {
const isMounted = useRef(false);
useEffect(() => {
if (!isMounted.current) {
isMounted.current = true;
return;
}
fn();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [deps]);
};