Transcript from the "Challenge 8: Autocomplete, Part 2" Lesson
>> Mike North: Let's think about what we can do with these stateful components and channel it toward enhancing our app a little bit. So let me go through the instructions, and I'm gonna take you to the code and show you what's been added to the picture. It's gonna look like, the last exercise we've just completed with my solution in place for what you've just built.
[00:00:23] And your job is gonna be to go upstream one level and to address a different part of the problem now. So there's a PlaceSearchResultList, right, that contains, think of this as the UL that contains all of the LIs which you just made, right? You made that component. And we've got a function now that kicks off the search process, given the strength.
[00:00:51] So, now we have an input and we're wiring up a function there, so we're gonna have to deal with a function type. The app owns the process of calculating those search results. So that is a job for the outer component outside this thing. When that search completes, or in fact, when any state changes in that app causing everything to rerender.
[00:01:18] This ResultList will rerender, and that can happen, as you type a new letter in or it could happen as we kick off the process for going to fetch data and now we're in progress and we might wanna render something different on the screen for whether we're in process.
[00:01:36] So, I want us to focus on handling all of those different states. Whether we have, we haven't kicked search off yet, or we're currently in progress or we have some results that we wanna display using a component that is very very similar and possibly even identical to what you just built.
[00:01:57] We're gonna see some use of async/await here. So, we're gonna lean on that and I'm gonna explain how async/wait gonna work, just in case this is new to some people. But, it is fine to leave this in place. We're going to outlook in the last exercise that I'll have you do because our job is gonna be to create similar behavior using only a generator function and code that we write.
[00:02:22] The name of the exercise here is called autocomplete-2, if you wanna open it up in your editor right now. So, if we open that folder up
>> Mike North: And look at the app, so there's some additional behavior here that we were not seeing before. First off, the app has some state, this is a proper stateful component and it's got a result set, a boolean indicating whether a search is currently underway.
[00:02:55] So this would be like there's a pending promise that has not yet resolved, and the current search term. So when we initialize that state, type scripts helping us here, if we were to leave this out, we would get a complaint saying, you gotta these are required. You have to do that or you have to declare something as optional, right?
[00:03:18] So we get type safety there. Note that we have no props being passed into the app, so it's fine for us to use an empty object as the interface there. I would in fact prefer and empty object over any, can anyone guess why.
>> Mike North: What's the difference between them?
>> Speaker 2: Cuz then you know you have nothing.
>> Mike North: Yep, exactly. So here if I try,
>> Mike North: This is wrong, it's saying, you're giving me something I didn't need. So it is a way, the shape of an empty object, empty props. And so now, there's no way for my fellow developer to put something there, thinking it's gonna do something.
[00:04:02] And maybe they keep going down that wrong road for a while before they realize, wait a minute, it's not asking me for anything.
>> Speaker 3: Couldn't they even put any there, pass something in, and then actually get it as a prop too? So then you're not even using any structures?
>> Mike North: You could and in the code review you'd say what's with this any?
>> Speaker 3: Exactly, yeah totally totally.
>> Mike North: In fact here's something else we could do.
>> Mike North: There's
>> Mike North: I forget whether it's a typescript configuration or an ES lin. Option here, but
>> Speaker 3: Just makes an easy legal.
>> Mike North: Yeah, or basically like at least make it a warning.
>> Speaker 4: It's a tslint, a tslint.
>> Mike North: Yep, so let me try that, do you know what the name of the rule is by any chance?
>> Speaker 4: No dash any.
>> Mike North: Great. Yes, so we would go down here.
[00:05:12] And again, this one else says JSON configuration. So there you go, no any, disallows any use of any. [LAUGH] And at that point now like here we can actually do it. Can we do like a 1 here? Is it gonna let us warn, so we won't do that because our code is not tightened up enough yet where that would even be okay.
[00:05:36] But if you're, if you're building like a library, I mentioned yesterday, which is an incredibly complicated, very type heavy project. There I can totally imagine that they would say. Any's are a liability, wherever they are, that's dangerous. We forbid it in this code base. Maybe not the best idea for an app because the whole point is, this is supposed to be light and flexible.
>> Speaker 5: Async function. [CROSSTALK] What?
>> Mike North: Do you know what it returns?
>> Speaker 5: It doesn't return a generator.
>> Speaker 6: Uses promises in a synchronous way?
>> Mike North: Yeah so you see it returns a promise, async functions return a promise. You're almost correct, it is sort of an abstraction around a generator function. You can pause the execution in the same way that you can with the generator function.
[00:06:53] And when we define a function as async like this, and for any of your own functions, or in fact, any function that returns a promise, it's fair game to put async in front of it. Then we can use the await keyword, and what the await keyword does is it pauses execution locally just within that function.
[00:07:15] Waits for a promise to resolve and then completes the assignment with the resolved value of that promise, which is really, really cool. For one, it lets us do something like this, which this is unheard of in the dealing with async code world. And as of TypeScript 2.5 we can even have catch here that doesn't require arguments like this.
[00:07:43] So that just dropped earlier this month. Oops we're not allowed to do that.
>> Mike North: Something like that would be totally fine. We can try catch, we don't have to .catch all of our promises, right? Async in a way is fantastic. So just know that this is asynchronous code that is written very much like synchronous code.
[00:08:09] So if we just focus on this here, I don't expect that the set state to cause something to be thrown. But just normally this would be suspect right where we're setting inProgress to true and then inProgress to false both within the same function. Well you're thinking like well this is gonna run really quickly right?
[00:08:26] Like why would you flip flop like within the same function. Just know, this is an Ajax request here. Oops, well that's an Ajax request or fetch. This is a fetch. And so it may be a full second before you actually reach this line here. So in the same way that the while true looked funky in our generator function, this also looks funky, but we have to remember that we're pausing execution and re-entering the function at those awaits.
[00:08:57] So hopefully you're starting to see that this, a lot of what I'm talking about here seems conceptionally similar to the generator functions we were just talking about, and this is no accident. Generator functions and yield are the basis for the async/await and the way it works. It's not an accident that most of the time once a browser launches support for a generator function, async and await comes either in the same release or very shortly thereafter.
>> Mike North: I wanna show you one last cool thing. It is just as it’s relates to async and await. Hopefully, this is the right version of Chrome.
>> Mike North: Nope. Unexpected identifier, okay let me try something else. So this here,
>> Mike North: Is it gonna cooperate with me? Nope, I have one version of Chrome open and it doesn't wanna let me do another one.
>> Mike North: Fine, I'll kill all the Chromes. All right, so now we're looking at, this is the nightly build of Chrome.
>> Mike North: So forget all the notifications and stuff here cuz I'm on the Google homepage. But I do want you to see.
>> Mike North: I have to use https, mixed content.
>> Mike North: Fine I'll use something with improperly set course headers.
>> Mike North: So that, that was a promise. Fetch returns a promise that resolves to a response. So in this next version of Chrome, starting with Chrome 62, you can even use await in your console without having to wrap it in an async function or anything.
[00:11:12] It's almost like you're already inside the context of a generator function when you're within your dev tools, right? I could do something like this, .then response, it's gonna complain at me about redefining resp.
>> Mike North: And that's actually the JSON from my API, available basically on the next line of code.
[00:11:40] All right when I ask for that variable. So that's the essence of async and await, the fact that it lets us write asynchronous code that returns a promise almost as if it's asynchronous code. So feel free to leave this in place, but just know that you're gonna wanna pass a string into this search function.
[00:12:01] And that will ultimately kick off the process by which inProgress and results and term end up changing. So if you're gonna wanna basically pass a function into this component that has the input, unlike whenever there's a keystroke or something, it's gonna trigger a new search which will do the appropriate rerender.
[00:12:21] The place search, yes?
>> Speaker 3: So then with async, if you call, if you have, if you're trying to a variable definition and you call an async method, they return something. Does that variable definition type, it's not a feature or something, it's actually just gonna be whatever type is returned?
>> Mike North: Can you give me a line of code to write, cuz it could mean a couple of different things there?
>> Speaker 3: Definitely so, if try search returned the response.
>> Mike North: Like this?
>> Speaker 3: Perfect, yeah.
>> Mike North: Okay, and you're saying what is the type of X?
>> Speaker 3: Yes, sir.
>> Mike North: It's a promise.
>> Speaker 3: It is, okay.
>> Mike North: But what about this? Sorry.
>> Speaker 3: What? So even if you had returned on line 26 results?
>> Mike North: Line 26.
>> Speaker 3: So if you'd returned something that all ready awaited, would it still be a promise?
>> Mike North: If you returned something that all ready awaited?
[00:13:28] So let's try it. So try search is type, what it returns is a promise that resolves to an array of place details. In this case, trySearch did not return anything, but it returns a promise that resolves to an array of place details. So if I add this one back in or places.
>> Mike North: Something like this, the type of places is a promise that resolves to place details, add this.
>> Speaker 3: Cool.
>> Mike North: And now the error here is, I'm not in the context of an async function, and so it's not gonna be able to pause execution. But TypeScript is smart enough to know that basically a way it's gonna cause, it's gonna make it so that that promised is resolved and it's the resolved value that we get back.
>> Speaker 3: Well, also 25 is not locking. It's not stopping the code.
[00:14:48] It's not blocking. Think of this, remember the case switch statement and just think of it as like this is one case. Sorry, I can't highlight it correctly, but one case does all of the lines above the selected content, stops where the selection stops on its left side. The next case basically does, goes here and it runs, finishes the assignment goes over here.
[00:15:15] So this should give you a little sneak peek into where we're eventually gonna go. Imagine an iterator that returned promises, and remember when we fed that stuff into the .next function? It completed the assignment. So imagine if we called iterator.next and when the promise resolves we put that resolve value back into the iterator back into the next function it completes the assignment.
[00:15:40] And then we pull off the next promise in the chain. This is how async and await works. We kind of saw it in action already. And we are going to implement our own async and await using this idea of an iterator, but promises other thing that controls how fast we're looping through that iterable collection of things.
[00:16:01] Got it?
>> Speaker 3: Totally. Thank you.
>> Mike North: Sweet. Okay, so your job in this challenge, we're gonna implement this PlaceSearchResultList. What I have it doing currently is logging some stuff out, I just attempted to make it so that you use it in its current form to kind of debug things.
[00:16:21] It should just JSON stringify whatever props you pass it. The PlaceSearchResultList can remain a stateless functional component, and this is where you typically wanna separate any complicated rendering from complicated state management. So the app's job, it's basically like you could argue this is what we would call a container component, and its job is just sort of kick off this request and rerender its children when necessary.
[00:16:57] But, it's never gonna cause itself to rerender, right? Cuz it has no statefulness in and out itself, that it depends on. It's just gonna basically change any props that it's passing to this PlaceSearchResultList. So this is a good pattern to use with react, that it keeps you from accidentally double or triple rendering through manipulating one's own state.
[00:17:23] So you separate those concerns, you either own state, or you render, you're either a container or your presentation only. So implement this PlaceSearchResultList, and I can show you what your target looks like and I'll add it to the slides here. [SOUND] Sorry, get my terminal,
>> Mike North: What did I change?
[00:17:48] I did the tryCatch,
>> Mike North: So you're gonna start up autocomplete-2, MPM start, not MPM test and over here,
>> Mike North: When we look at our browser,
>> Mike North: Now we should be able to typing something like coffee, so note that we have three situations we can be in, number one, nothing's been typed yet.
[00:18:31] You could use a search term of length 0 to figure out you're in this situation. Once we type something in, we're showing results and those were probably cashed they came back really fast. Let's search for something I haven't searched for yet and you'll see a currently inProgress indicator.
>> Mike North: Right? So we saw that we were waiting for that promise to come back. So this is the state that we're keeping track of, this is what our state full container component's all about, showing while we don't have results yet, something in the meantime, or telling the user to write something in the text box above.
[00:19:11] So let's take a half hour for this and by the end your solution should look and work something like this. If you want to, I wouldn't advice you cheat yourself out of this exercise, but you could certainly switch to the solutions branch, start up the same exercise and drive it just to see kind of the behavior that you're aiming for as a goal.
[00:19:35] And again, don't worry about passing those tests exactly, they depend on that exact structure of HTML. But just in concept, you should be able to show no search term has been entered, a search is currently underway, meaning you have a pending promise. And then finally, here's a list of results and the components we just built there's a form of it there that you can use to render out.