Check out a free preview of the full TypeScript Fundamentals course:
The "Challenge 9: Solution" Lesson is part of the full, TypeScript Fundamentals course featured in this preview video. Here's what you'd learn in this lesson:

Mike walks through the solution.

Get Unlimited Access Now

Transcript from the "Challenge 9: Solution" Lesson

[00:00:00]
>> Mike North: We're gonna go through the solution to this ninth exercise where having already tackled the task of a stateless functional component for the placed search result item. And having already handled some switching in the render function, based on props passed in to that list component we just finished.

[00:00:22] Now we are going to take on the task of dealing with this state management ourselves, right in this place search container component. This is a very common pattern that the container presentation component pattern. Very common for the purpose of making sure that you separate state management from things that render state.

[00:00:46] In order to reduce potential causing of oneself to re-render. So the first thing I'm gonna do here. No, actually let me before I do that make sure that I am running the correct app.
>> Mike North: This is autocomplete 3, that's the name of this exercise. Let's refresh and see where we're at.

[00:01:12] It says replace this with the search result list, we'll do. And we're getting yelled at here for not passing in the correct result, the correct props. If we look at the props that this expects, there it is. It wants us to pass in results in progress, a search term, and an un-search term changed.

[00:01:37] So some of that we have available, or we had available in our last exercise. But let's see where we're at, I'm just gonna leave myself a little bit of a note here. So we need, actually, yeah, this is a fine place to put it.
>> Mike North: Just gonna copy this so that we will be able to come back and address that.

[00:02:03] So a list of results whether the search is in progress, the search term itself, and this function whether it's changed or not. Let me grab that function type just for completeness. It takes in a string as an argument and returns, we don't care. That's what void means, it returns we don't care.

[00:02:22] So note that this place search container has empty object types as both its state and its prop's interfaces. We are going to not worry about props for this particular component, but we do need to worry about state which is this first one here. I'm just gonna call this IPlaceSearchContainerState, and we'll define that up here.

[00:03:01]
>> Mike North: And I'm just gonna basically make it these first three terms. Similar to what we had in the last exercise, right? What that'll let me do is make this component happy by doing the same thing we were doing before. This state, need one more dot, and then this last thing we can handle more explicitly.

[00:03:23]
>> Mike North: On search term changed equals this. Begin search, and let's see do we take care of binding it? We did in this case. We bound that to this component so that whenever it's invoked, we will get the calling context we expect. We can treat it as executing in the context of this component.

[00:03:46]
>> Mike North: And let's see, what is it complaining about now?
>> Mike North: So that's optional, those are passed in, okay. So now, we don't have anything for this .state. That's what it's complaining about. This is an empty object here.
>> Mike North: Sorry, I've got this reversed. Props comes first, state comes second, now this will complain and this will be happy.

[00:04:13] So our place search results list is happy. We've sort of moved the error up too. Now the component we're looking at right now says when you initialized your state, you gave me something that was not allowed. You can't just pass an empty object, these things are required. You have to give me something that matches this shape.

[00:04:30] So we'll say results is new array in progress. We start out not being in progress. And the search term is an empty string. So now we've satisfied the minimum conditions for making this work. And if we type something in, nothing happens. The reason being nothing is in this function.

[00:05:08]
>> Mike North: But the function is being called so now all we have to do is sort of wire this up. This is gonna be an async function. You could either call it an async function or have it return a promise. If I call it an async function, I can use a weight inside it.

[00:05:25] So I'm going to choose to do that. So first thing, we're gonna setState. Our search term is gonna be set updated, right? Based on this event that comes in, we will update the current search term. And we will say inProgress is true.
>> Mike North: So now we should start to see a more interesting message coming through already.

[00:05:52]
>> Mike North: Great, so now we sort of switched into this other mode, where we're saying this component knows that there's a search underway. And if we delete everything, we're back into the empty search term case, so that's handled. The next thing we want to do is leverage this auto complete module.

[00:06:11] So, we've got this thing, it returns a set of place details from a given search term. So, we're gonna pass the term in there, and we'll say,
>> Mike North: Let results equal await autocomplete. So just looking at this here, one of the things I hope you take away from this workshop is a lot of the code you write does not have to have explicit type definitions all over the place.

[00:06:45] There is nothing on this line that is a type definition. In fact, there's nothing in the line above that's a type definition. We sort of define some types up front, some structure, and then wherever type script can infer, it does infer. And we get the benefit of knowing that this function returns a particular thing.

[00:07:04] And in here, we say we return a promise that resolves to PlaceDetails. But if we got rid of that, it would still work. Particularly with return values, TypeScript is pretty good at figuring out what you're returning, right? So even in here, there's not, I mean we say we need an argument to be passed in.

[00:07:29] Arguments are sort of there you do need to set up some structure. But the rest of this, I mean, it looks kinda like of like regular java script. Even this, we don't need this, that's just for your benefit here as developers, so you can look at this file and know that's what it is.

[00:07:45] But the fact that this already returns that thing, cuz it was cast here, so that's gonna give us the exact same types throughout our system. So I want you to just not litter these type annotations everywhere. That is a common mistake when people start jumping into TypeScript, to just go nuts with these things.

[00:08:04] If you can remove a type annotation, and your editor still says yeah, I can still tell you that that’s the same type, it’s better to omit it than to have it there. Having it there doesn’t really give you all that much additional safety in a situation like this.

[00:08:21] But it does kind of make the code a little more difficult to read. And makes it harder for other people who are more experienced in JavaScript than in TypeScript to sort of jump in and reason about this code. But here like we have as much type safety as we ever could and we're not littering annotations all over the place.

[00:08:42] So then what we can do is now that we'll have the results we're basically gonna pause here. And even within the atuocomplete there are other awaits, right. So we're gonna await for this async function to resolve. We'll get that result sent back and then we can do this setState, results, and then in progress false.

[00:09:10]
>> Mike North: So I'm just gonna move these comments around so they correspond to the appropriate lines. So initiate a search using the autocomplete module. When the problems resolves, update your state accordingly.
>> Mike North: What are we doing wrong here? SetState, maybe we didn't save or didn't refresh. There it is coffee coming through.

[00:09:43] Any questions about this?
>> Mike North: All right, cuz this was the slow pitch right before the fast ball. We're about to hit the hardest exercise in the whole course, but it is a pretty rewarding one.
>> Mike North: So, let's close this stuff down. Let me make a quick commit.
>> Speaker 2: I have a question but I don't want to derail us.

[00:10:16]
>> Mike North: Ask away.
>> Speaker 2: So, I just noticed that if I type one letter and delete it, in the search bar it still actually did the search.
>> Mike North: Yes.
>> Speaker 2: How could, and I think I understand why.
>> Mike North: Mm-hm.
>> Speaker 2: Because the async is resolving after I have set my search result state, all right?

[00:10:39]
>> Mike North: So, what's happening is a race condition.
>> Speaker 2: Right.
>> Mike North: Where with each letter, each letter that goes out, right? When we type a few keys, we're basically saying go and fetch some updated search results. And we pass it a callback and say, when you arrive back update your page, right?

[00:11:00] And so if we send out four of these, you actually see four refreshes on the page happen. This is a typical challenge people run into when working with promises, where they're not cancelable, right? So, it's almost like we wish there was a way where, for the next event, we can kind of disregard anything that's currently in progress.

[00:11:26] So once we complete this next exercise I will be able to show you how we can logically take that next step. And essentially baked into areas that our app doesn't need to worry about on a case by case basis. Set up a cancellable asynchronous chain of events where basically between every promise we examine to see whether we've been cancelled yet.

[00:11:49] And if we have we just stop, that's one of the great powerful aspects of generator functions.
>> Mike North: That's not a side track. That's exactly where we're going.
>> Mike North: Sorry, there are a lot of branches, but video watchers will appreciate this.
>> Mike North: All right.