Skip to content

Conversation

@stipsan
Copy link
Member

@stipsan stipsan commented Oct 4, 2022

Fixes bugs related to React StrictMode as well as other minor nits

// Eagerly subscribe to sync set `entry.currentValue` to what the observable returns
// @TODO: perf opt opportunity: don't setup sync subscription initialValue is !== undefined
// Why not check `initialValue`? Because it might change during re-renders, but here we're only concerned with the first run
// if (entry.currentValue === undefined) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tested this optimization and I didn't find any regressions.
However, given the scope of how it potentially impacts Studio v3 internals, I decided to comment it out for now.

]
}, [observable])

useIsomorphicEffect(() => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this side-effect is only needed to clear up memory after unmounting it's not necessary to use useIsomorphicEffect/useLayoutEffect. The sync subscription ensures that, if possible, record.currentValue will have a value on first render and we don't have to pay the perf cost of useLayoutEffect (with its render + block browser paint + layout effect + render + allow browser paint flow).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great insight, thank you!

Comment on lines +63 to +64
if (shouldRestoreSubscriptionRef.current) {
if (store.subscription.closed) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two checks ensures that the hook can be called out of order, and enforces a subscribe => unsubscribe => subscribe => unsubscribe symmetry no matter what React might decide doing in the new v18 features.

// React StrictMode will call effects as `setup + teardown + setup` thus we can't trust this callback as "react is about to unmount"
// Tracking this ref lets us set the subscription back up on the next `setup` call if needed, and if it really did unmounted then all is well
shouldRestoreSubscriptionRef.current = !store.subscription.closed
store.subscription.unsubscribe()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using store from the setup function, instead of doing a getOrCreateStore(observable, getValue(initialValue)) like before in teardown, it's ensured that if observable changes identity we don't "forget" to unsubscribe old stores and leak memory.

Co-authored-by: Cody Olsen <stipsan@gmail.com>
@bjoerge bjoerge merged commit 021510f into sanity-io:current Oct 5, 2022
bjoerge added a commit that referenced this pull request Oct 5, 2022
Co-authored-by: Cody Olsen <stipsan@gmail.com>
Co-authored-by: Bjørge Næss <bjoerge@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants