Autoplay

    Refactor a Higher-Order Component to a Render Prop Component

    Andrew Del PreteAndrew Del Prete

    In this lesson we look at two React components that render a Chuck Norris joke and share common functionality via a Higher-Order Component. We'll refactor this Higher-Order Component to be a Render Prop component to help make it easier to reason about.

    reactReact
    javascriptJavaScript
    Code

    Code

    Become a Member to view code

    You must be a Member to view code

    Access all courses and lessons, track your progress, gain confidence and expertise.

    Become a Member
    and unlock code for this lesson
    Transcript

    Transcript

    Narrator: 00:00 I have a couple of components here that share functionality by a higher order component. Now on the top right, I have a Chuck Norris joke that I'm pulling from the Chuck Norris API. On the bottom here, I have a more advanced version of that which has the joke, the category that the joke is in, and the URL and this nifty little button you can click and give you a new joke.

    00:22 Let's go ahead and look at our code. The top example is a functional component called joke. Below, I have a similar component called joke advance. It has quite a few properties for us to use.

    00:30 Let's go ahead and look at where I'm invoking these here. As you can see on line 52 and 53, I'm passing my joke and my joke advance component to something called with Chuck joke. Then I'm assigning it to a new variable called nerdy Chuck joke and nerdy Chuck joke advance. Then I am calling that from within my app component here.

    00:49 One of the main reasons why we want to use something like the higher order component or the render prop pattern is for coder use. What they give us is a way to abstract out common logic and state to a place that we can consume with our components without using to duplicate code everywhere.

    01:05 However, one of the downsides of the higher order component pattern is that it's really difficult sometimes to figure out where things are actually coming from. We look back up at our component here. You can see that it is expecting a joke parameter. If we look at where we're actually implementing this component, we're only passing it a category.

    01:24 Where is that joke coming from? This creates some level of indirection and some confusion for the developer because we really have no idea where that's coming from unless we dig and find out it looks like we're passing our joke component to something that may be decorating or embellishing it a little bit. We have to check there.

    01:40 Here we have our with Chuck higher order component which really is a function that we've passed a component to as a parameter. This could be joke or advanced joke or whatever else. It returns a class. This class has state, a fetch joke handler, and on mount, it goes ahead and fetches an initial joke for us.

    01:58 Finally, we return the component that we've passed such as joke or advanced joke. We pass the state and handlers we need in order to make our component reusable. That way we don't have duplicate code in each of our joke components. It's just in one spot. We use it. All that to say is that we get the abstraction and the code reuse that we want using the higher order component.

    02:17 Personally, it's a little hard to reason about. I'm going to go ahead and refactor this higher order component to use a render prop pattern. Let's go ahead and copy our component here and create a new component called Chuck joke.

    02:32 The first thing that we're going to need to do is remove our function since we no longer need that. We'll make our class our default export. We'll name this Chuck joke, save it. I'm going to comment out the return value in our render method because it's going to look quite a bit different.

    02:49 We'll replace it with this.props.children. This is where we'll pass it the common handlers and state that we need in our component, fetch joke, loading, and joke. What's happening here? Our component expects that the children prop should be a function that receives an object. This is where we can pass in common state and handler functions.

    03:11 Now let's import this component into our app and refactor our joke and joke advance components to use it. The first thing that we're going to need to do here is wrap our joke component with Chuck joke. Then we'll pass a function to it which becomes the children prop we looked at earlier and give it a destructured object for our parameter. We'll put all of our rendered HTML inside of it.

    03:37 We'll also replace the joke prop with category and pass it down to our Chuck joke component to be used by our fetch joke method. Next, I need to dismantle the higher order component here and just use joke directly.

    03:51 All right, that looks like it works. Let's go ahead and do the same for our joke advance component. Again, just like before, we'll wrap our component with a Chuck joke component, pass it a function with our properties, and then move our rendered HTML inside of that function.

    04:12 It looks like I may have forgotten to add the URL in the Chuck joke component. Let's go ahead and add that. Now that that's done, let's disconnect joke advance from our higher order component and just call it directly at the bottom.

    04:30 It looks our refactor from a higher order component to a render prop component is a success. Now we have this nice syntax to work with. It's clear where everything is coming from.

    Discuss

    Discuss