Exposing child functions using imperativeHandle and forwardRef

Hyo
dooboolab
Published in
3 min readJan 21, 2020

This story is about a way to expose custom functions to parents in react or react-native.

@dooboo-ui TinderCard element

Eunho Lee has recently contributed to @dooboo-ui/native, a beautiful react-native element, TinderCard.

Many of you may be familiar with this UI since it has been known as an innovative UI/UX around the world. Therefore, we’ve also thought of implementing one in our UI library for react-native.

Currently, the features are pretty simple.

  • You can swipe your card on the right or left.
  • You can undo your swipe.
  • You can swipe a card just by pressing the button.

If you have thought of building a TinderCard, you may have a question on where to put LEFT/UNDO/RIGHT buttons as shown above in the gif image. Should they be placed inside the library element or expose render functions to parents?

Well, I thought of exposing just the functions without doing any of the above. I just thought it would be the best scenario as being a UI library.

So how to achieve it?

Below are the steps to do the above job.

1. Use forwardRef inside the child element.

Note that the `forwardRef` is a function in `react` library.

2. Use imperativeHandle to expose the functions to parents.

We want to expose `handleCancel` and `forceSwipe` in this case.

3. Expose typescript typings for typescript users.

Export interface `TinderCardRef`
Add typings for the `TinderCard`

4. Use it in parent with useRef.

Now go back to where you want to use TinderCard.

Note that the `typings` are provided separately in the package. If you have any better ideas, please give us a `PR`.

Then add ReactElement in your parent element.

<TinderCard
testID="tinderCard"
ref={tinderCard}
onSwipeRight={handleUnlike}
onSwipeLeft={handleLike}
onCancel={handleCancel}
data={data}
renderCards={_renderCards}
rotate
stackSize={0}
/>
<TouchableOpacity
onPress={(): void => {
tinderCard.current.forceSwipe(TinderCardDirection.LEFT);
}}
><Text>LEFT</Text></TouchableOpacity>
<TouchableOpacity
onPress={(): void => {
tinderCard.current.handleCancel();
}}
><Text>UNDO</Text></TouchableOpacity>
<TouchableOpacity
onPress={(): void => {
tinderCard.current.forceSwipe(TinderCardDirection.RIGHT);
}}
><Text>RIGHT</Text></TouchableOpacity>
You can see that the typescript is working correctly.

That’s it!

You can see the full source code in our first PR.

The remaining issue is passing generic type to Props interface and removing any for the item type. I found it pretty tricky to pass generic props to RefForwardingComponent. I hope someone can help us out of the box.

Update: Jongtaek Choi has contributed for generic typing in #137 🎉

--

--