Transcript from the "Prop Getters Solution" Lesson
>> Kent C. Dodds: So let's go ahead, and I'll work through this solution. We've got our test running and we've switched to the exercise version. So what's failing right now is getTogglerProps isn't defined. We're not passing it from our getStateAndHelpers function. So let's go ahead and define it. And this is, [COUGH] sorry, it's going to be a function so, [SOUND.
[00:00:26] And actually I'm gonna extract it from this and getStateAndHelpers just to keep it separate. So we'll say this.getTogglerProps and we'll put it right here, it's going to accept props. As we see in our usage here, we have some props that we wanna play to the button, so we gonna accept those props.
[00:00:45] And the first thing that we wanna do is make sure we return object that has all those props. And so, if you passes an ID, I don't care. You want that ID, that's fine, I don't care. But I'm gonna pull off a couple things I do care about.
[00:01:00] So I'm gonna actually gonna destructure this and pull out everything else that I'm not pulling off myself. So some things I do care about are onClick. It's actually the only one I care about. And in this case, instead of the onClick that you provide, I'm gonna provide my own, onClick is a function.
[00:01:22] And this thing is going to call their onClick with all the arguments, args onClick args. And then it's also going to call this.toggle.
>> Kent C. Dodds: And not always will onClick be provided. So let's do onClick. This is one case where I'm cool doing just ampersand, ampersand, cuz, I don't know.
[00:01:50] I don't know why I'm cool with that, but I like it.
>> off screen male: [LAUGH]
>> Kent C. Dodds: So this.toggle. What is happening to, wait. [SOUND] So the problem is this is not bound to anything. But I mean, arrow function
>> Kent C. Dodds: [SOUND] What is wrong? Sorry, I'm gonna have to cheat. Sorry, sorry, sorry, don't look at me.
[00:02:14] Yeah, I just, that's weird. Sorry, I just write it a little bit less or more terse. I'm not sure why that's any different though.
>> off screen male: It's probably cuz it's a class method. Yeah.
>> Kent C. Dodds: Wait, what?
>> off screen male: Yeah, that's it. It's not a bound function.
>> Kent C. Dodds: You're right, you're right, you're right, thank you.
>> Kent C. Dodds: [SOUND] Thank you so much. So actually we're missing something, we also need aria-expanded. So that's my bad, cuz that should throw an error. But yeah, so that's the basic idea. It's kind of annoying to have to write this, especially if you have several of those. So I have a little utility that I have in downshift, this callAll.
[00:03:04] Which is kind of hard to say, but it accepts any number of functions and returns a function which accepts any number of arguments. And then for each of the functions, it's going to call it if it exists with all those arguments. So effectively, it's the exact same thing as this, except made generic.
[00:03:23] So we'll just say callAll, this.toggle and onClick, and that works just the same. This is really handy and now we don't actually need the toggle props anymore. And they can just do that. We could even simplify this further, which is what I do in the final example that you'll be working with.
[00:03:51] It's implicit return I think.
>> Kent C. Dodds: All right. Yeah, Mark?
>> off screen male: Adrian has a nitpick. Shouldn't we toggle first in case the given function blows up?
>> Kent C. Dodds: Shouldn't we toggle first? Good question. So before, in my first example, it was onClick was called first and then this.toggle was called.
[00:04:14] And Adrian is asking, so what if this onClick function blows up? Now our toggle function won't be called. Yeah, that's true. If the onClick function blows up then we can't really reasonably rely on the state of the world anymore anyway. And so, I wouldn't concern myself with that.
[00:04:34] If you want to, you could add a tri catch to this. But if something unexpected happens, then updating the state probably will still have unexpected results anyway, so it's not worth the concern. Also, I prefer to do my own work internally before I let other people operate, so that's why I have toggle before onClick.
[00:04:59] I can't really justify that though, so it is what it is. [LAUGH] It's just personal preference. Actually I sort of can, so in downshift, we don't have an exercise for this. But what if I don't want the built in onClick to fire. Well, in downshift you can add like monkey patcher property onto the event.
[00:05:21] That's called disable downshifts default or built in, or some weird thing. It's very edge casey. But then, I have this callAll event handlers and it's not gonna call any additional event handlers if that property is set to true. So you can go look in the source code for that.
[00:05:41] It's pretty edge casey, but it's a useful mechanism for people to hook in and say given the state of my component, I don't want you to do your normal thing. We have other mechanisms to control state, and so that's one of the reasons why I'm not showing you how to do that.
[00:05:59] But that's something that you could look into as well. Another thing that we're not gonna cover, but you might also consider is you could create a button component right here as a helper. And then this could be responsible for rendering your switch or whatever, golly gee. It could be responsible for rendering a switch.
[00:06:25] And then users here could pull out the button and render that button. And so, it could have all the props be populated and everything else and then they could add additional props. The reason I don't like that is because I like giving users complete control over how they're rendering stuff.
[00:06:41] And so, I feel like prop getters are a pretty good way to give that freedom and also have a pretty nice API. But that's something else to consider. You can really do just about anything with the Render Prop API and what you're passing to the consumer. So let your imagination run wild and do some fun things, make mistakes, take chances, and get messy, all that stuff.