Handle static properties properly with Higher Order Components

Kent C. Dodds
InstructorKent C. Dodds

Share this video with your friends

Send Tweet
Published 5 years ago
Updated 3 years ago

One of the goals of reusable components is that the implementation details are unobservable. You want to make things work the way people think they should work without them having to consider the implementation. In this lesson we'll see a confusing observable behavior of using Higher Order Components and use the hoist-non-react-statics library to avoid the problem.

Instructor: [00:01] Your toggle component's been around for a while. People have started using it, and somebody comes to you and says, "Hey, listen. I've got this myToggle implementation that has a render method with a button, and it's pretty cool."

[00:11] Then I added a static property on this myToggle called toggleMessage. Then when I went down to render it inside the toggle component, I said myToggleWrapper.toggleMessage. I expected that to work, but it didn't. It threw this giant error, and I have no idea what's going on.

[00:30] It says that this is undefined or something. What's the deal? You say, what's actually happening is myToggleWrapper is not the same thing as myToggle. The toggleMessage is available on myToggle, but it's not available on myToggleWrapper.

[00:47] Then you say, I'm exporting the myToggleWrapper. I'm not actually exporting myToggle, and I don't want to have to decide which is which. I basically want to have it so that when myToggle is wrapped with this width toggle higher order component factory, what I get back is going to have all the same static properties that I expect exist on myToggle.

[01:08] I can use it just like myToggle was, and the fact that it's using a higher order component is not really observable. We're trying to solve the problem that using a higher order component is observable. We want to make that as inobservable as possible.

[01:21] We want to make it so that when people use this, it's as natural as possible. Basically, we need to take all of the static properties on the component that we're wrapping, and add them to the wrapped version of that component.

[01:34] We could just iterate through all the keys on the component, and apply those to the wrapper, but we don't want all of those things. If we specify a display name on myToggle, then I don't want to override the wrapper's display name.

[01:46] Also, context types, I want to keep those. We pretty much want to keep all the React-specific ones, and only hoist up the non-React ones. There's actually a library for this for hoist-non-react-statics. I'm going to go ahead and add a script tag up here at the top of the page for that.

[02:05] Then we can go down here to our wrapper implementation, and instead of returning the wrapper, we're going to return hoist-non-react-statics with the wrapper and the component. With that, everything should be working just fine.

[02:21] We get that warning when we turn the button on and off. What this library is essentially doing is it's taking all of the static properties of the class that we pass in and applying those to the wrapper class, but only those which are not React static properties, like display name, context types, or prop types.

[02:42] Doing this makes the fact that we're using a higher order component when we export the myToggleWrapper a little less observable, so that folks using the myToggleWrapper can use all of the statics that are available on the underlying component without having to worry about the fact that they're actually using the wrapped component. We're doing this using the hoist-non-react-statics library.