The Scrollable Component Exercise
- Write a
scrollable
component that, that takes in a specificwidth
andheight
as props (via thestyle
prop). - The content (passed through
children
) of that component must be larger than its width and height. - Each time the component mounts, the user should see the most bottom content, NOT the top OR the middle.
- The parent of this
scrollable
component, must have two buttons one for scrolling to the top and the bottom and the component. - Try implementing the same functionality twice. One using
useImperativeHandle
andforwardRef
and the other, without using the two. - Explain the difference between the two implementations.
- Will you use
useLayoutEffect
oruseEffect
for 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
scrollable
component's state - Scrolling up and down will cause rerendering of both the
scrollable
component 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
scrollable
component will not be very reusable, we need to add an additional state to any component that needs to use thisscrollable
component 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 componentandthe child usessRef
to expose the properties that the parents could have access to. - In this case, the properties exposed are the functions
scrollToTop
andscrollToBottom
. 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
useLayoutEffect
vsuseEffect
- We need to scroll to the bottom when the component mounts
- If
useEffect
is 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 on each rerender. - This won't happen with
useLayoutEffect
as the effect will be applied before the browser repaints, NOT after - Note: We can use a different strategy of creating a
useDidComponentMount
hook withuseEffect
if we really don't want to useuseLayoutEffect
Notes
forwardRef
is a React feature that lets a component take aref
from its parent component- Keep in mind that
useRef
doesnât notify you when its content changes. Mutating the.current
property doesnât cause a re-render - Sophie Au: React Hooks:
useImperativeHandle
- Mehdi Namvar: Reactâs
useImperativeHandle
by Examples - Chris: When to use
useImperativeHandle
,useLayoutEffect
, anduseDebugValue