Finally a proper use case

One day a colleague came to me and asked how to solve his problem, regarding outsourcing reusable logic, using React. The App he was rewriting was written in Angular.js before and there you use directives for generic logic.

He was working on a checkout form and has prototyped a class based dropdown component which is able to display a bootstrap popover if there is a validation error on submit. The popover should only appear, if the field is focused.

Custom select component in action

The component was working as needed and now my colleague wants to outsource the popover functionality to reuse it in every field of the checkout form. One could write a component which can be put into the render function of each field. Or something like a higher order component or a component with a render prop. These are all valid solutions. But with React 16.8 released just a few weeks before, all I could think of was: “Here it finally is. A real life use case for a custom hook”.

By the way: We use formik for our forms written in React with yup for validation.

But where should we start?

We didn’t know how our custom hook will look like in the end. And we didn’t need to. We needed to do it step by step.

In the end all came down to the following three steps.

Write a functional component using the built-in React hooks ( useEffect , useCallback and useRef in our case). Cut and paste all the hooks and helper functions which relate to your needed functionality into another function. Identify your in- and output. That’s basically the API of your custom hook.

And of course don’t forget to name your newly created custom hook starting with “use”. 😉 We called ours simply useErrorPopover.

Let’s try it out

We wrote a functional component:

* If you’re interested in what each hook is doing here, I provide additional information at the end of the article.

We moved the needed hooks to a second function.

And finally we have to define our API. But how should it look like? Our hook needed an error message and an HTMLElement to do its job. We could pass both as parameters to our hook without any return value. In order to make things even simpler for the consuming component, we decided to return a MutableRefObject . So the consumer doesn’t need to create it itself.

Our API became: (errorMessage: string) => elementRef: MutableRefObject

And the finished hook looked like this:

Our custom hook is ready to be used inside of each component we want to be able to display a popover.