1- import { DependencyList , EffectCallback , useRef , useEffect } from 'react'
1+ import {
2+ DependencyList ,
3+ EffectCallback ,
4+ useRef ,
5+ useEffect ,
6+ useDebugValue ,
7+ } from 'react'
8+ import useWillUnmount from './useWillUnmount'
9+ import useMounted from './useMounted'
210
311export type EffectHook = ( effect : EffectCallback , deps ?: DependencyList ) => void
412
@@ -9,6 +17,11 @@ export type CustomEffectOptions<TDeps> = {
917 effectHook ?: EffectHook
1018}
1119
20+ type CleanUp = {
21+ ( ) : void
22+ cleanup ?: ReturnType < EffectCallback >
23+ }
24+
1225/**
1326 * a useEffect() hook with customized depedency comparision
1427 *
@@ -40,20 +53,39 @@ function useCustomEffect<TDeps extends DependencyList = DependencyList>(
4053 dependencies : TDeps ,
4154 isEqualOrOptions : IsEqual < TDeps > | CustomEffectOptions < TDeps > ,
4255) {
56+ const isMounted = useMounted ( )
4357 const { isEqual, effectHook = useEffect } =
4458 typeof isEqualOrOptions === 'function'
4559 ? { isEqual : isEqualOrOptions }
4660 : isEqualOrOptions
4761
48- const depsRef = useRef < TDeps | undefined > ( )
62+ const dependenciesRef = useRef < TDeps > ( )
63+ dependenciesRef . current = dependencies
64+
65+ const cleanupRef = useRef < CleanUp | null > ( null )
66+
4967 effectHook ( ( ) => {
50- const prev = depsRef . current
51- depsRef . current = dependencies
68+ // If the ref the is `null` it's either the first effect or the last effect
69+ // ran and was cleared, meaning _this_ update should run, b/c the equality
70+ // check failed on in the cleanup of the last effect.
71+ if ( cleanupRef . current === null ) {
72+ const cleanup = effect ( )
5273
53- if ( ! prev || ! isEqual ( dependencies , prev ) ) {
54- return effect ( )
74+ cleanupRef . current = ( ) => {
75+ if ( isMounted ( ) && isEqual ( dependenciesRef . current ! , dependencies ) ) {
76+ return
77+ }
78+
79+ cleanupRef . current = null
80+ if ( cleanup ) cleanup ( )
81+ }
82+ cleanupRef . current . cleanup = cleanup
5583 }
84+
85+ return cleanupRef . current ?? undefined
5686 } )
87+
88+ useDebugValue ( effect )
5789}
5890
5991export default useCustomEffect
0 commit comments