-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix error occurring in useEffect
on hmr
#308
base: main
Are you sure you want to change the base?
Changes from 6 commits
441b1df
10ce0e2
61b16b9
4fbfb36
e9d1845
ff7cd3b
52bef46
820a8f7
23fb36a
20c773e
78c6037
2e24a7f
3f441e0
d3de5d4
ef925c6
a6af861
b377add
faf696a
8352c72
c0083e3
bef4639
652be84
8b0fdab
e329219
ad22a27
50f95ea
402ac00
420d291
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,7 +22,6 @@ export function useDisposableState<T = never>( | |
const preCommitItem = useCachedResponsivePrecommitValue( | ||
parentCache, | ||
(pair) => { | ||
itemCleanupPairRef.current?.[1](); | ||
itemCleanupPairRef.current = pair; | ||
}, | ||
); | ||
|
@@ -47,14 +46,23 @@ export function useDisposableState<T = never>( | |
[stateFromDisposableStateHook], | ||
); | ||
|
||
useEffect(function cleanupItemCleanupPairRefIfSetStateNotCalled() { | ||
return () => { | ||
if (itemCleanupPairRef.current !== null) { | ||
itemCleanupPairRef.current[1](); | ||
itemCleanupPairRef.current = null; | ||
const lastCommittedParentCache = useRef<ParentCache<T> | null>(null); | ||
|
||
useEffect( | ||
function cleanupItemCleanupPairRefIfSetStateNotCalled() { | ||
if (lastCommittedParentCache.current === parentCache) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Do we also need to have this check above, in the other There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The second one will not throw because it sets the ref to null. However, because of this, we will lose the current state, which is not perfect. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, seems better to not set it to null! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh wait, this should be good, because it will cleanup only when we set with a function and when the ref is still not cleaned up, hmr shouldn't be able to trigger it twice There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wdym? Which useEffect are you referring to? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. useEffect(
function cleanupItemCleanupPairRefAfterSetState() {
if (stateFromDisposableStateHook !== UNASSIGNED_STATE) {
if (itemCleanupPairRef.current !== null) {
itemCleanupPairRef.current[1]();
itemCleanupPairRef.current = null;
} else {
throw new Error(
'itemCleanupPairRef.current is unexpectedly null. ' +
'This indicates a bug in react-disposable-state.',
);
}
}
},
[stateFromDisposableStateHook],
); This one should cleanup only when these two conditions are met, reruning this on hmr has no effect. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I posted this stuff way too quickly. This will throw on hmr but I think just removing the throw should be enough |
||
return; | ||
} | ||
}; | ||
}, []); | ||
lastCommittedParentCache.current = parentCache; | ||
|
||
return () => { | ||
if (itemCleanupPairRef.current !== null) { | ||
itemCleanupPairRef.current[1](); | ||
} | ||
}; | ||
}, | ||
[parentCache], | ||
); | ||
|
||
// Safety: we can be in one of three states. Pre-commit, in which case | ||
// preCommitItem is assigned, post-commit but before setState has been | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,16 +23,24 @@ export function useLazyDisposableState<T>( | |
state: T; | ||
} { | ||
const itemCleanupPairRef = useRef<ItemCleanupPair<T> | null>(null); | ||
|
||
const preCommitItem = useCachedResponsivePrecommitValue( | ||
parentCache, | ||
(pair) => { | ||
itemCleanupPairRef.current?.[1](); | ||
itemCleanupPairRef.current = pair; | ||
}, | ||
); | ||
|
||
const lastCommittedParentCache = useRef<ParentCache<T> | null>(null); | ||
useEffect(() => { | ||
// react reruns all `useEffect` in HMR since it doesn't know if the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
// code inside of useEffect has changed. Since this is a library | ||
// user can't change this code so we are safe to skip this rerun. | ||
// This also prevents `useEffect` from running twice in Strict Mode. | ||
if (lastCommittedParentCache.current === parentCache) { | ||
return; | ||
} | ||
lastCommittedParentCache.current = parentCache; | ||
|
||
return () => { | ||
const cleanupFn = itemCleanupPairRef.current?.[1]; | ||
// TODO confirm useEffect is called in order. | ||
|
@@ -43,7 +51,7 @@ export function useLazyDisposableState<T>( | |
} | ||
return cleanupFn(); | ||
}; | ||
}, []); | ||
}, [parentCache]); | ||
|
||
const returnedItem = preCommitItem?.state ?? itemCleanupPairRef.current?.[0]; | ||
|
||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.