-
Notifications
You must be signed in to change notification settings - Fork 15
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
feat(useDataEngine): make engine instance a referential constant #934
base: master
Are you sure you want to change the base?
Conversation
73ffb74
to
631e674
Compare
This change assumes that apiVersion and baseUrl won't change throughout an app's lifetime (as these changing would mean we need a new link and engine)
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.
this is a good change! Here's a suggestion which might address what @mediremi mentioned (though I think those cases should be rare)
function useConst<T>(initializer: () => T): T { | ||
const [value] = useState(initializer) | ||
return value | ||
} |
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.
function useConst<T>(initializer: () => T): T { | |
const [value] = useState(initializer) | |
return value | |
} | |
function useInstanceVariable<T>(initializer: () => T, dependencies: any[]): T { | |
const [value, setValue] = useState(initializer) | |
const initializedRef = useRef(false) | |
useEffect(() => { | |
if (!initializedRef.current) { | |
initializedRef.current = true | |
return | |
} | |
setValue(initializer()) | |
}, dependencies) | |
return value | |
} |
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.
Maybe something like this instead, to support updates when deps change?
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.
Note however that this will cause double-renders on dependency updates...
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.
useInstanceVariable
would be used in DataProvider
and CustomDataProvider
instead of in useDataEngine
right?
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.
Sounds a lot like we could just use useMemo
instead of useConst
?
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.
@Mohammer5 this is super old... but no, there's a difference because useConst
guarantees referential integrity while useMemo
might re-initialize in certain situations since it is only considered a performance optimization.
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.
Yeah, I also figured out the other day that useMemo
does not guarantee that..
I think for simplicity's sake, the following might be the most pragmatic with the least amount of abstractions:
function useDataEngine = (): DataEngine => {
const context = useContext(DataContext)
const [instance, setInstance] = useState(context.engine)
useEffect(() => {
setInstance(context.engine)
}, [context.engine])
return value
}
I was trying to ensure that a hook preserves the referential identity of a function with jest by using the
rerender
function returned by@testing-library/react-hooks
'srenderHook
function. This will render the wrapper twice as well, which causes theengine
object to be created again. Any hook that makes use of memoisation doesn't work with this, so I created a hook calleduseConst
(inspired by @amcgee) and made sure that the engine only gets created once.