Convert a Render Props Component using a Custom React Hook

Elijah Manor
InstructorElijah Manor
Share this video with your friends

Social Share Links

Send Tweet
Published 6 years ago
Updated 4 years ago

Render Props is a popular pattern in React, but sometimes the nesting of Components can get quite deep. Thankfully, React Hooks can help provide an alternate way to structure your code for reuse. In this lesson, we will take an existing Render Props Component and convert it to use a hooks instead.

Instructor: [00:00] Here, we have a small React Todo app. Let's kick up a dev server and check out its features.

[00:06] You already may see something that is a bit odd for a todo app. There are some numbers to the right of each item. That is the height and width of each row. If we resize the viewport, the numbers change. We could programmatically respond to those values.

[00:19] In this case, the background gets striped and animated if a line wraps. If we check that item, the animation stops. Let's take a look at how this code works and see how we could convert it to use hooks.

[00:33] We do import a helper module called element-resize-event to get notified when the size changes. If we scroll down a bit, there's a space render props component that uses the element-resize-event module, and will provide the height and width of that component.

[00:50] Some key points are creating a ref, unmounting, and actually passing the height and width to the children function.

[00:59] You may have not written a render prop before, but you may have used one. Down further is where the space render prop is being consumed. We provide a function to the space component, and it'll invoke that function, passing the height and width. From that point, our code can use those values as it chooses.

[01:18] In our case, we pass it to the item component. If the height is greater than 53, then it should be striped. If it's not complete, then animate it. We also display the height and width to the right of each item.

[01:32] Let's get rid of the space component and solve this with hooks instead. We'll also remove the space render prop component definition as well, which means we could remove the component and create ref from our imports. However, we'll need to add useRef, useState, and useEffect for our hooks.

[01:53] First, let's create a ref for our wrapper and set it to the useRef hook. Then we'll destructure height and width, and a setSize updater from useState, passing an initial value of width and height .

[02:08] Next, we'll introduce a useEffect hook. We'll pass it a function to invoke and inputs to watch. It will pass an empty array to only run on initial mount and unmount. Inside our callback, we'll invoke updateSize, which we haven't defined yet. Let's do that now.

[02:27] UpdateSize will pull out the element from our ref and invoke the setSize updater, passing the height and width at that point in time. Then we'll leverage the element-resize-event module, telling it to listen to resizeEvents on our ref, and callUpdateSize if any occur. To clean up, we'll return a function and call element-resize-events unbind method, passing our ref.

[02:56] Lastly, we'll need to pass our ref into the item component. In our case, item is an emotion component, so you pass refs to it within a ref. Now, if we go to test our app again, when we resize it, it should behave as it did before when we had a render prop. It does. Yay.

[03:15] One last thing before we leave. Let's come back and combine our hooks into a custom useSize hook that accepts a default size. To do this, we'll grab all the code from the useRef through the useEffect that we added, and move that into our custom hook.

[03:34] We'll replace the initial state with the default size passed into our hook. Since our hook doesn't directly need the height and width, let's simplify that to size. We'll let the consumer destructure that further if they want. At the bottom, we'll return an array that contains our size, state, and the ref that was created.

[03:55] Now, let's use our custom hook. We'll call our useSize hook, passing default values of height and width , and destructure height and width, and the wrapper ref, which we're already passing to item on line 55. That should be that.

[04:12] If we come back over and run the code again, we'll still have the same behavior as before, but this time, we have a custom hook that we could possibly use in other components. Yay for reuse.