Exposing properties to the parent
Summary: Create a scrollable component such that its parent could control whether the top part or the bottom part is shown. There shouldn't be any flickery jumpy behavior. Implement it twice, one with
useImperativeHandleandforwardRef, the other without. State the difference between the two.
- Write a
scrollablecomponent that, that takes in a specificwidthandheightas props (via thestyleprop). - The content (passed through
children) of that component must be larger than its height. - Each time the component mounts, the user should see the most bottom content, NOT the top OR the middle.
- The parent of this
scrollablecomponent, must have two buttons: to scroll to the top and the bottom and the component. - Try implementing the same functionality twice. One using
useImperativeHandleandforwardRefand the other, without using the two. - Explain the difference between the two implementations.
- Will you use
useLayoutEffectoruseEffectfor this? Explain why.
My Solution
By using useImperativeHandle and forwardRef my implementation is like this:
You call the component like this:
If you don't use useImperativeHandle and forwardRef you may end up with a component like this:
And you will call the above like this:
Thoughts
If we don't use
useImperativeHandle- The parent component will manage the
scrollablecomponent's state - Scrolling up and down will cause rerendering of both the
scrollablecomponent and its parent component . Normally these things are okay, but it's added unnecessary complexity, which we don't want especially if the parent is also managing alot of things. - The
scrollablecomponent will not be very reusable, we need to add an additional state to any component that needs to use thisscrollablecomponent as their child.
- The parent component will manage the
Using
useImperativeHandle- The parent component can customize an instance value that belongs to the child component.
- The child component exposes properties via
useImperativeHandle. The parent component must forward aref(in our case we named itsRef), to the child component. The child usessRefto expose the properties that the parent can access. - In this case, the properties exposed are the functions
scrollToTopandscrollToBottom. Both functions manipulate the dom node the child renders - These properties are exposed via the line
useImperativeHandle(ref, () => ({ scrollToTop, scrollToBottom })). - The parent will be able to access the functions exposed to it like this
sRef.current.scrollToBottom()
Using
useLayoutEffectvsuseEffect- We need to scroll to the bottom when the component mounts
- If
useEffectis used, you would see a flicker, a jumpy behavior. Briefly, the screen will flash to show the contents at the top prior to scrolling to the bottom. - This won't happen with
useLayoutEffectas the effect will be applied before the browser repaints, NOT after - Note: We can use a different strategy of creating a
useDidComponentMounthook withuseEffectif we really don't want to useuseLayoutEffect
Notes
forwardRefis a React feature that lets a component take areffrom its parent componentKeep in mind that
useRefdoesnât notify you when its content changes. Mutating the.currentproperty doesnât cause a re-renderChris: When to use
useImperativeHandle,useLayoutEffect, anduseDebugValue
Quotes
useImperativeHandlecustomizes the instance value that is exposed to parent components when usingref. As always, imperative code using refs should be avoided in most cases.useImperativeHandleshould be used withforwardRef.
It allows us to expose imperative methods to developers who pass a ref prop to our component which can be useful when you have something that needs to happen and is hard to deal with declaratively.
It gives you control over the value that is returned. Instead of returning the instance element, you explicitly state what the return value will be
It allows you to replace native functions (such as blur, focus, etc) with functions of your own, thus allowing side-effects to the normal behavior, or a different behavior altogether.