Check out a free preview of the full A Tour of JavaScript & React Patterns course:
The "Compound Pattern Solution" Lesson is part of the full, A Tour of JavaScript & React Patterns course featured in this preview video. Here's what you'd learn in this lesson:

Lydia codes the solution to the Compound Pattern challenge.

Get Unlimited Access Now

Transcript from the "Compound Pattern Solution" Lesson

[00:00:00]
>> Okay, let's look at the solution for this provider pattern, or a compound pattern exercise. So the first thing that I like to do is to create just a separate file where we're going to store this component. And I'm actually just going to move a lot of functionality from input to FlyOut.

[00:00:17] So don't get confused now, I'm just going to copy paste. So the first thing that I'm gonna do is I'm gonna get rid of this. So we gonna create like a FlyOutContext. FlyOutContext is React.createContext. This is going to keep track of the state of our FlyOuts, or yeah, or compound components and see if it's open values, stuff like that.

[00:00:38] Then we're going to create the FlyOuts which is just going to be the provider. So the first thing that we're gonna do is return.provider. It doesn't auto close, I'm used to that it auto close, I guess then prompts a children's gonna get props here. And the value that we pass here is, again, like that functionality that we see here.

[00:01:00] So we wanna get the open toggle. Yeah, so we have the open setOpen value setValue, or I guess we just have toggle actually because it uses to setOpen. Okay, cool. So now we have this FlyOut which I'm just going to export. And then we also want to add, what else was it, the FlyOut.input and List item and ListItem.

[00:01:30] So the FlyOut.input, export function or actually it could just be a function input, which was gonna get props. So this one is going to consume that provider that we just created here. So I need the value, toggles, setValue is Reacts.useContext. I could have just created a separate hook for this, use FlyOutContext but I haven't done that.

[00:01:54] So here, which then again returns this input, Okay, return, input. Now this is already using the toggle, value, setValue, all the stuff that we had before. And then I also need to create a list, again gets props. This one just needs to know if it should be open or not, so that's also get passed to your open, return open.

[00:02:27] Let's see how we add that here. So we have the open FlyOut list is going to copy this. We didn't include the open there. I think I did. Yeah, return open. Now it doesn't care about the actual listings, it just needs to render this UL and then the children that we eventually pass to it, or props that children serve.

[00:02:51] And then we also need to create a list, there. And then we also have an item, props, and that is just going to be this little list item here. And this doesn't need to key, just needs to know the props of children. Okay props, and then we're going to use the setValue from this context.

[00:03:20] So we're going to get setValue. I need to return it obviously, return. So I'm just going to add another proper, it's gonna be like props up value. This is kind of similar to what we saw in these examples, just to make it easier to set the value, wait, now we got it, this value, to essentially, or to eventually set the state.

[00:03:46] So on mouse down so when we click it we set the value to that props up value that we pass. All right, so now we have the list, the item, and the input components and is throwing an error now because it's duplicate. But to make this a compound component we just need to say FlyOut.Input, FlyOut.Input is equal to the input component.

[00:04:07] FlyOut.List is equal to list component, and FlyOut., I think I probably didn't have the, yeah, flyout.listItem is item for example. All right, so now we have our compound component, the FlyOut component. So now we created the context. The FlyOut itself is provider like we saw before, so this one contains the state and passes it down to any children.

[00:04:32] And we see that the children here, they use this context, they consume this context which they can then in turn use. So in the input component we can now just import this FlyOut. FlyOut, hopefully I exported it, I may have forgotten to do that. Okay, no, I did not.

[00:04:51] So we can just do return. I'm just gonna create it here, FlyOut, nope. Then first we have the FlyOut.input. Now does doesn't need any props or anything, we're just rendering the input right now. But you can see here it's just the input. But then we also want to render the list which is attached to that input, so we have the flyout.list.

[00:05:21] And within this list we want to render these list items. Now these list items are based on the listings that we map here. So we can still use this part, But then instead of just rendering a ListItem here we do FlyOuts.ListItem. FlyOuts.ListItem, cool. So now we just set the value is listing.name.

[00:05:47] Okay we don't need this anymore, we also don't need that. We do need a key because we're still mapping over React components, and it also expected this value prop here in FlyOuts. So, now let's see. Return, We can get rid of all of these things. Let's see. Okay, so now when we refresh, [LAUGH] Wait, where did it go?

[00:06:25] Let's see. Are we rendering the Flyouts, input, list? FlyOut.list equals list. Let's see if it's open or not. True, FlyOut.list. Maybe I don't have the right CSS selectors here, let's look at the solution right here. It could also just be stuck, this thing again. This is the solution that I wrote down here is the exact same state as where I left the other one off, so don't worry.

[00:06:56] So we can have this FlyOuts, and in here, Yeah, so we're not actually using this. So here in the input, one thing about the compact component is that we can just use these return components whatever we want. If we wanna somehow render three inputs we could do that if we want to.

[00:07:18] Is not my friend today. Anyways, normally you would see three input components just because it doesn't care about the component itself, it will just render whatever will pass his children. So the compound pattern is a really nice way to create those dynamic flexible stateful components, and kind of have this plug-and-play method that you both, like I said, often see unlike those component libraries.

[00:07:43] Yeah, so this is a really good example of where it is useful for smaller context to use the provider pattern. Because it was super easy for us to just create a context and share the state with so many child components. We don't know what the child components are cuz we can dynamically render them.

[00:07:59] And the child components only care about certain values, so it's really nice to destructure them from the context that way. Yeah, any questions? I know this is a lot to take in cuz it's a combination of many things that we just covered. So I completely understand if it's still a bit, okay, but why would you use it?

[00:08:23] Of course also, this website will always be online so if you ever wanna read back what we did today, free to check that out. Sure, yeah, what's the question?
>> Can we use the memo and useCallback to avoid rerendering issues?
>> It depends on the data that you're getting, but yeah, usually you can use useMemo and useCallback to ensure that we aren't unnecessarily updating the states.

[00:08:52] In this case, I mean, this is not specific to the compound pattern, this is just specific to, I guess hooks in general. So, in some cases you may not necessarily need to reupdate a hook if the end result stays the same. In that case we can memo-ize the results or memo-ize the actual function that we pass to the useCallback to make sure that we don't generate another hook for that specific.

[00:09:18] Or create another function for that hook, if that makes sense. I'm really bad at explaining those two hooks because they are so specific, but once you know the difference between useMemo and useCallback, they return the same result, they have the same use case. But useCallback expects a function, whereas useMemo expects a value, as far as I know.

[00:09:41] But yeah, these are very useful hooks if you are using data that are within a component that shouldn't rerender too often. But if it's highly dynamic data make sure that you're not using useMemo where it shouldn't. Cuz then you might actually end up with the opposite where you're, why is my data not updating?

[00:09:56] Why is my component not updating? It's because it's using a memo-ized value. Yeah, those are the built-in hooks. I mean, if you get started with hooks, definitely make sure to check them out because the React core team, they expose so many useful hooks that you can use to get really good performance website.

[00:10:16] So you don't have to use all the community hooks, but it's definitely good to know what's out there and what you can use to decrypt performance, stateful components. Cuz of course it's always an issue with React, does it render too often?Where do I put the state? But yeah, it's a different way of thinking about things with hooks, I guess.