This course still contains valuable patterns in React, but doesn't cover React Hooks introduced in React 1.16.
Transcript from the "Higher Order Component Solution" Lesson
[00:00:00]
>> Kent C. Dodds: Let's go ahead and implement this really quick, we'll swap the exercise final for the exercise, get a bunch of error messages and stuff. You'd be surprise how hard it was for me to validate that you're doing things properly. You can check out the test later but yeah, all of our work pretty much is gonna live within this width toggle component.
[00:00:21] The funny thing about this function is it's called the higher order component but it's neither a component nor is it higher order. It's a function that returns a component, so yeah. But that's what it is called. And so that's what we're gonna do here. So we're gonna create a component and, for us, we don't need any lifecycle hooks, so we'll just do a function component called wrapper.
[00:00:45]
>> Kent C. Dodds: And the wrapper component is going to use our render prop. And now that we're using the provider pattern, we just wanna access the toggle component that we're accessing or that we're inside the context of. And so we're going to return Toggle.Consumer. And then this is going to accept our Toggletils or whatever you wanna call it, and it will render the component that it's given.
[00:01:16] So higher order components can be given any kind of argument. Often it's gonna be given a component but you could pass an object that configures a component. You could pass anything and any number of arguments. There's nothing special about a higher order component passing just a component to render.
[00:01:34] So in our case, our wrapper is gonna accept props. When we come back here to Subtitle, Subtitle is actually the wrapper that we're gonna return. And so when Subtitle is rendered, it’s gonna be rendered with some props. And so we’ll just forward that onto the underlying component. So part of the objective of a higher order component is to make it so that consumers of our components that are created with this can not tell that it is in fact a higher order component.
[00:02:08] It should behave as close to possible as the component that it's wrapping. So that's why we're forwarding all the props on. We're also going to forward on a prop called toggle, toggleUtils. And so in our case, this stuff props.toggle.on and it'll be able to tell cuz we're passing onto toggle.
[00:02:35] With React history, that's gonna be react router that will be this.props.match and history. And then React Redux this.batch and that kinda thing. So very similar type of thing and so let see, yeah we are also gonna want o return the wrapper and will say that and see what are testing.
[00:03:03] So here we wanna make sure we use a react forward graph and passing the graph property to a random component. So, yeah, this one's kind of tricky and it's only sometimes the real problem. But, here where we're rendering this subtitle component. If we wanted to get a reference to the essence of that component, we would say, here's my ref.
[00:03:27] Instance this.i = i. Whatever. To assign it and then we can call methods on it. Whatever else. And so part of the whole idea of the higher order components is to make the fact that it is a higher order component unobservable. And unfortunately with the way that React works, this.
[00:03:47] Instants that its' gonna be passed into ref is actually going to be an instance of our wrapper. Which is, in this case, that also doesn't work because it's a function of mine. So if this was a redux class, in any case, it's not going to be giving us the thing that we want.
[00:04:07] And so React recently released a nice new feature called, here let's assign this Wrapper to React.CreateRef. It's pretty handy. What you give React.CreateRef is a function. I will change this to an arrow function. That accepts props and a ref here. And then we'll say ref equals ref. And so it'll forward all the refs so the fact that this is a higher order component wrapper is totally unobservable.
[00:04:40] You can use the ref as you would expect. And that was like a really, really serious restoration before create ralph was around. Because normally what you'd do is you'd say accepted props dot enter ralph and people would have to use the nrf profs and it's like super annoying so yeah, that's no longer an issue.
[00:05:01] Great, so we'll save that. And I think I messed up this. Let me get rid of that ref. Okay, no I didn't mess it up. There we go. Let's just move on. I'm pretty sure that's gonna be something else Okay, so we created our wrapper. We created the forward ref.
[00:05:28] Now in React Dev Tools, if we pop this open and go to React, if you don't have this installed, definitely get this installed. It's gonna show us the components by their display name. and in our case if we look at, here we'll look at the, man. Well it's busted so we can't even look at it at the moment.
[00:05:52] But the display name that it's showing to us like app right here and browser router and all that stuff, that's coming from a display name property that's on each one of these components. And so right now the display name property for this is actually undefined so we'll say unknown.
[00:06:09] So what we can do is just say Wrapper.displayName and give it something that's useful. So we'll say withToggle. It's pretty common to say like whatever the higher component is And then whatever it’s wrapping. So we’ll say component.display name or component.name. So display name is coming from react if you’re using vowel it will actually create that for you dynamically on the fly which is pretty cool.
[00:06:34] If you’re not or if it doesn’t work or something, then name is just a regular JAVA script thing. That’s the name of the function. And so that kind of helps with that. I think I like busted something, because it should be. Ha, I'm using the wrong API. Create or forward ref.
[00:06:56] Nobody caught me.
>> Speaker 2: [LAUGH]
>> Kent C. Dodds: Just kidding, it's late so. Or it's been long. Okay so now we need to do this silly thing. So this is like this whole all these weird handles. This is why people who implement higher order components don't like them. Because it's like all these things you have to do to make it so that You can pretend that this component wrapper is actually the component that it's wrapping.
[00:07:27] So, here's subtitle, and like I said this is a little bit contrived, but this subtitle is actually this class. We have a display name. We have these static properties. Display name is a react static property. That's fine, we're going to be rendering it anyway. But this emoji and this text are gonna be referencing subtitle, so subtitle.emoji and subtitle.text.
[00:07:53] It's totally reasonable to expect to be able to do that. I'm just saying, hey, make me a component that's like this one. So the problem is that it's not like this one because it doesn't have all the same static properties. So, well this component does have the emoji and a text.
[00:08:09] The wrapper does not and so we need to whist those properties on to the wrapper. Likely for us this is such an annoying problem that somebody wrote a module for STUs, so we don't have to do this ourselves. It's called HoistNonreactStatics and we use them like this. Hoist them onto the wrapper from the component.
[00:08:34] An that gets our test passing. So there are like four other steps before forwardRef and stuff came along but it's kind of annoying to implement these. That said, it does provide often a simpler alternative to render props in some cases. So I do recommend having it. I wouldn't create it before somebody asks for it, but I don't have a problem creating and exposing these in a library.
[00:08:58] It's pretty small, it's not hard to maintain. Yeah?
>> Speaker 3: Could you just quick go over what hoist nonreact statics is doing again, sorry.
>> Kent C. Dodds: Sure, yeah, sure. So hoist nonreact statics, down here this subtitle is actually this wrapper. So we're creating this wrapper function. And the subtitle does not have the static properties that this react class has.
[00:09:21] So, we're defining static emoji and static text. But, if you just were to look at this code, with the whole idea of higher order components in general, you might expect that I could use sub title just like I would be able to use this component. So that's why we say sub tittle emoji, sub title text.
[00:09:40] We should be able to, especially if we're exporting this like often in Redact you'll do export, default, connect my or like your you know whatever your maps state to props and all that stuff and then my component. And so you want whoever importing this component, you want them to be able to treat that exported component just like they would the MyComponent.
[00:10:09] And so that's where we're, I'm kinda simulating that here in this contrived example, But yeah, in general that's the purpose, is just to help make the fact that this is a high order component or a wraps component, totally unobservable for users