React Project: Recipe Search App (using TypeScript)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so typescript is becoming increasingly popular when coding up react apps and it offers a lot of safety when you're actually coding of components and what sort of data they can accept and if you've got typescript on your resume or cv it's definitely appealing as a junior developer so in this tutorial we're going to be making a recipe searching app and it'll be using typescript to actually type the data that's coming back from an api and also the data that's being used within the rest of the app and being passed to various different components so let's take a look at the app and start coding okay so as always let's have a quick overview of what we're building uh today before we actually start getting into some code so we're building this simple recipe search app and if i type in something to the search box such as fish for example uh what will actually happen is there'll be a request that goes off to an api and actually get these results from the providers database so you can see here they've got some thumbnails and some placeholders if the thumbnail doesn't exist and we've also got the ingredients that are used and the link if we actually click on it should take us to the actual url where the recipe came from in the first place so just to point out this data is coming from an api provided by recipe puppy and there was a slight problem when i started to use this in that they don't accept cross-origin requests so we're going to have to proxy the data from their api via a simple node script we did something similar in a previous tutorial but we're just going to move through that part of the tutorial quickly because that's not really the point of the tutorial we're talking about typescript in this tutorial and how you can use it within your react apps and likewise for the ui design i'm sure you guys can come up with something a lot better than i can but again that's not really the point of this tutorial so the point of the tutorial really is to introduce you to a little bit of typescript and how you can use it in your react app so let's just do one more search save for apples and there you go we've got some results for apple recipes from the recipe puppy api okay so that's an overview of the app we're going to make a start on the project now so we need to create a new react app some boilerplate react code but we need to configure it to use typescript files rather than plain old javascript files so you could do that manually by creating your own web config and perhaps i'll do that in another tutorial but for this tutorial we're going to actually just use the create react app and it provides us with a handy option to actually create an app with typescript setup already so let's just go over to our terminal so if you have a create react app installed globally you can call it directly from the command line here or if you don't and if you've got a modern version of node you can use the mpx command to say create react app and then let's give it a name so we'll say recipes and then we pass in the option of template and then for that we can then ask create react apps to use the typescript template so what this will do is create a new react app called recipes and it will configure it to use typescript which is what we want for the tutorial today so i'm just going to run that now and it might take a few seconds just to install all of the dependencies for you okay and once that's done let's just go into the directory that's been created and open that up in visual studio code and let me just rearrange my window so they're side by side and before we have a look at the code that that's created for us i'm just going to set up the api proxy for us so this is something that i won't be going into detail in this tutorial as i mentioned we did something similar in a previous tutorial where we created a job search app so i'll put a link to that in the description below and the server code i'll include in the github repository as well just so you don't have to worry about that so let's just create an npm script for that and there are actually a couple of other dependencies that we're going to need to get that working axios for sending network requests and chalk some output on the terminal but once those are installed we should be able to npm run start api and you can see that proxy server is now listening on port 3001 so again don't worry too much about that proxy server uh just it will be included within the github code so you can run that straight away without having to worry about what's going on there okay so the actual code that we've created is going to look very similar to any other javascript react tag that you've worked with before but the first thing you might notice is that all of the files have got the tsx extension where it would have been jsx before or js and that just means that they're typescript files that can handle jsx type syntax and we get the same sort of style of app when we create a react app with typescript so just from another terminal we can say npm run start which would start the app for us and you can see that starts a development server for us and we've got our blank react app set up so there are several other files included here which probably haven't seen before for setting up things like testing and also the environment for typescript as well and handling they're using quite a lot of the default typescript setup as well so we don't necessarily need to make any changes in there so this tutorial we're just going to be focusing on how you would use typescript within your react code so with that said let's actually start making our recipe app using typescript so i'm just going to first of all do some resetting to get rid of some of the stuff that we don't need in here such as the logo i've got our blank page setup and the first thing we need to do before i start writing any jsx or tsx i guess in this instance is to create a bit of state so as we've done in previous tutorials we're going to have some state to hold on to what data we want to display to the user so i'm going to say some recipes found so this would be an array of items that have been found from the api when a search has been performed and also for the actual input box as well we'll have a recipe search bit of state and set recipe search is the setup for that and we can just default that to an empty string to start off with okay the next thing i'm going to do is actually create a function called search for recipes so this is what we'll actually call out to the uh proxy api that we've created and that's going to basically be an arrow function that accepts a uh a query that we actually send to the api and then the result of that because we're in an async block we can use await is fetch and the url we have the api running on is 3001 and we just pass a query parameter of search again this is just how the proxy api has been set up and we passed that query option to the proxy script to actually do the request and once we've got that data back we just get its json equivalent and there is actually a property in there called results and i'll show you that in a second when we actually send some network requests just in case what's going on but you might have noticed that we've got a little bit of a problem here um we've got a linting error saying that we've got a problem with our parameter that we're passing in so the linting area is saying we've got this implicit type of any being passed into the function and what that basically means is that the function that we've created is accepting an argument and there's no problem there but typescript doesn't know what type of data is being passed in so the way we specify a type in typescript is any variable arguments or function that we're creating you can actually put a colon after it and then specify what type you want to use so for example if we say we're expecting our query to be of type string then you notice the error goes away and that makes sense because we're actually using that query variable inside of a template literal of course if we were using another type of data being passed into this function we could specify it as number there and then if you try to actually do some kind of operation on that variable that doesn't exist on the type of number so for example if you wanted to try and split the string by a certain character in it you'll see we get a typescript compilation problem here is just saying that we can't do that because the split function doesn't exist on type number so this is like the first benefit of typescript really is just to show you that it will prevent you from doing things in your code that you can't do on certain types so if you set the query variable back to a string again you'll see that the error goes away here because we can actually call the split function on a string okay so i'm not going to go into much more detail into the benefits of typescript and a lot of its features but we're just going to carry on coding up our react app bearing in mind that we can use types to specify what type of data we're handling within our code so what we can also do with typescript with our function here is to actually tell it what type of data we're expecting back so we can say we're expecting a promise back but you can't just specify that it's any old type of promise it actually needs to be a type of promise or the data that the promise will actually return rather and you do that with these angle brackets here and then specify what type is going to come back so we don't exactly know what type of data is going to come back at the moment so we can use the any type however with typescript you can create your own types and then specify those in your data that you're using and we'll be doing that in just a moment and we'll be updating this to use our custom type rather than any type here so that is our search function i'm just going to create a use effect hook here and again this will have an async function inside of here and one thing we need to do is the query needs to be encoded if there's any special characters in there if there's any spaces or anything like that so let's use encode uri component to encode the recipe search state that we've created and then the response is basically going to just call that search for recipes function that we just did so so await search for recipes and we just pass in the query variable that we've created uh note again that the typescript compiler will complain if you try and pass in a data type that doesn't match what the function says it should have and you can say there it's complaining that the number is not assignable to a type of string but no worries legs we are using a string and once that's done we'll just set the recipes found to the response that comes back okay so let's try and get our search working and to do that we're going to need to put some markup in here just so that we've got a search box to uh type into so first of all we've got recipe search app is the title of our app oh and there's an error there so on line 14 okay so yeah i think uh the user effect function uh yeah that async function inside there i didn't call it so yeah there we go that's got rid of that error there for us okay so we're going to create a form and let's just give this a class name so we can style it later on so it's a search form is the class name and inside of there we're just going to have an input and i'm going to give this an id of uh search text x we'll be using that in a moment and the only other thing we need in here is a button to actually trigger the search and we'll just say search okay so when this form is submitted we want to actually trigger the effect and call the api so we'll say for on submit oops curly braces here we get an event and i'm going to call a function called search which i haven't created yet and pass in that event object so let's create that search function up here okay so we've got our function set set up here and it's got an event and we've got the same sort of problem again so it is okay to leave arguments and variables with out a type if you really need to but uh obviously we should always be aiming to put the right types in to make our code actually use the power of typescript so uh what is the actual type going to be for this event object that's passed into search where you can get some clues if you actually look at the function that we're calling down here so the on submit function if we hover over the uh event object here so vs code hopefully tells us what type of event is being emitted so it's a react form event which is actually a generic type and the type of that is the html form element which makes sense because we're missing an event from this form element here so we can actually just use that type up here we can say we want this event type here to be a form event and then just use the form element type inside of the angle brackets and you see typescript is now happy with that okay so if you reference that event object now you can see in our vs code intellisense we've got all of the properties that are available on this type of object that we're referencing so event dot prevent default should be there so we want to stop the page from submitting and reloading once the user submitted the form and then i want to get a reference to the form so we actually say a variable form is the event dot target so the next thing i want to do is get a reference to the input and i can do that by using the form object and then calling a query selector on it and passing in the id of search text so there are obviously other and better ways of getting the value out of this search text input box down here but i wanted to do it this way just to show you a couple more typescript things so you notice that typescript is complaining about the query selector function here saying it doesn't exist so what's going on there like we should be able to call a query selector on a form element to get its inner child components well if we actually log out what we've got here for form in the console we should see that that does actually exist on there oops i just noticed that the uh api is just constantly firing there at the moment so we should probably stop that happening and uh we'll do that in the use effect here by setting up uh dependency on recipe search so it's doing on load which is probably still not great either so let's just say um we'll only run this code if query has actually any uh value in there so let's just save that okay so if we reload the page now we shouldn't uh get any calls to the api until we've made a search so yes back to the console uh and if we hit the search button in here you can see we've got the form element and if we just put that into a variable real quick temp 1 and we want to call the query selector function that's available on it for search text so that actually did work in the console with some plain javascript so why doesn't typescript accept that in our actual source code well the reason for that is that the event.target that is being passed back from this event variable is actually coming back as an event target type which is fine but it doesn't actually give you the full description of what type of target has been retrieved so with typescript we can actually cast things to a particular type as long as we know that that type is the correct type that is going to be passed into that particular variable so we do that with the as keyword and we say html form element is the type of element that is going to be passed back from event.target and you can see now that the error that was coming up for query selector has now disappeared so we're going to need to do a similar thing when we actually access the input box so if we want to set the recipe search that has been provided to us to input.value you'll see we get a complaint from typescript that value doesn't exist on this type of element and that's because typescript doesn't know what type of element's been returned from this query selector and whether that has a value or not because obviously some html elements don't have a value property so we can cast that again to a html input element and again you can see the error disappears okay so that's a pretty uh tricky way of creating a search function but hopefully it's demonstrated a few things in typescript and how you can overcome them but if we actually now go into the search box and type something in and click search if we go to our network tab we should see that we've got a successful search going to the api for garlic okay so uh just to point out as well in the uh search for recipes function i was pulling out the property of results because this is the data we get back from the recipe puppy api and obviously results is where we want to get all of our data so wouldn't it be great if we could actually say our search for recipes function returns a promise with this data but also what type of data it is and we can do just that with typescript by creating our own custom types so we want to say we've got an array of data items that are coming back that have a href ingredients thumbnail and title so let's go over to vs code and actually create a new type and it's simply just a case of creating a new typescript file so i'm going to create a file called irecipe.ts and there's a bit of a convention when you're creating a new interface which is what we're doing here to prefix the file and the actual name of the interface itself with an i standing for interface so i'm going to follow that convention here so i'm going to export an interface of i recipe so what does irsb have well it has a href which is a string it has some ingredients if i can spell which is a string it has a thumbnail which is a string and it also has a title which is a string so it might look at first glance there's not much value to this because all we're doing is specifying that we've got this data type that's just got a load of strings on it but you'll see how that's quite useful in just a moment so to use our recipe interface it'd be good to say that we're returning from our recipes search for recipes function here a promise that has those data items included so we can replace that any type here by saying we're going to get an array of i recipes let's just import that so now typescript knows that when we call this search for recipes function we need to pass in a query variable which is string and also it's going to return a promise which has an array of eye recipes returned so that's okay but we're actually getting a problem down here now when we actually try and set the recipes and that's because this state up here for sets recipes found doesn't really know what type of data it's setting so all it knows at the moment is it's going to be initialized with an empty array and then we try and put in an array of eye recipes into there so you can see this error here is just saying that the types are not compatible but that's okay because we can specify what type of data is going into our state by using the angle brackets again up here and just say this state is going to accept an array of i recipes and you can see the error disappears okay so now we've got some strongly typed data being pulled in from the api and then we can use that within the rest of the app and then make use of the features of typescript to actually tell us more about the data that we're working with so in order to move any further with this i think we're going to need to create a component for our to display our recipes so let's add some mark bin for that and then create the component so after the form uh if we've got some data for the recipe search uh we're just going to put a p tag in here that just says results for uh recipe search just to let the user know what they were searching for let's put some ellipse on the end of that and then after that we'll create a new div which has a class name of recipe container say recipe container and if we've got any recipes found if there's any items in that array if there's a length there what we can do is say for each recipes that are found what we'll do is we'll map them and we'll get the recipe and then pass that to create some jsx and i'm going to be creating a recipe component in just a moment and so for the key we could use an index but the href should be unique for each recipe that we pull back so if you look at the recipe variable that's been passed in here you can see it's already been passed in the type of eye recipe because typescript has told react that this is the type of data we're working with inside of recipes found and i can then use intellisense inside here to say right i've got my recipe what do i actually want to pull out of there and you can see all of the properties that we set up in the iresp interface so let's use the href as a prop for the recipe component i'm just going to pass in the whole recipe okay so obviously that's complaining so we haven't actually created the recipe component so let's do that now so to create a new component with typescript we just say give the file a name and recipe component.tsx and it's pretty much the same as what you would do normally in creating a functional component with react so recipe component is a function and export default recipe component and we should then in our app.tsx file just be able to import that and you can see that's been imported for us but you can see we've still got some errors and if we hover over first of all it's telling us that we're not returning any jsx which we know we haven't created anything yet but you can also see that the recipe prop is here and you can see that it's complaining that that recipe prop doesn't exist on the type so that's really helpful because if you do forget to pass in any props or passing the wrong type of props a typescript will warn you about it so let's sort that out in our arrow function here so we're going to be receiving a variable pasting called props and what does that have well it has a recipe property on there which is of type i recipe so that just tells react that our props has a recipe prop on there and that is the type of our recipe and if we look in our app.tsx file now you can see the error of the prop that was getting before is now gone okay so from here it's literally just a case of creating this recipe component the first thing i'm going to do is just destructure recipe from props and then let's actually return some jsx code as well okay so we'll have a div inside of here and we'll just give that a class of recipe and then we'll create another div inside there which will hold the sort of top of the recipe card and i'll just call that title we'll create an image inside of there which has a source attribute of recipe dot thumbnail again you can see the intellisense is giving us a hand there because it knows what type of data we're working with but if we don't find that if that's a null as some of them are in the recipe puppy api we'll just go straight to localhost 3000 so that's this app and there are i'll put an asset in there of placeholder.jpg so anything over here in the uh public directory i'll put this placeholder.jpg file in here again i'll put this in the github repository so you don't need to go and find your own placeholder image but essentially if the thumbnail is empty we'll put that as the uh as the image to be displayed for our old text let's be complete here let's say uh we use the recipe dart title okay so that should handle our image for us we'll put a p tag in here and recipe.title okay and then once we've done that what we're going to do is going to display the ingredients that are inside of the recipe but we're going to display in a kind of uh list so if we do have uh ingredients because again some of the recipes may not have that we're going to have a ul and inside of there we've got recipe dot ingredients and i'm going to split that string as a comma because it's literally just a long string with all of the ingredients listed so that'll give us an array and then we can map those for each ingredient and again just to show you uh react or typescript knows that uh ingredient is a string because the split function will return an array of strings okay so for each of those uh we'll just inside of a list item element we'll just display the ingredient okay and then finally we're just going to have a href which will be the recipe href and just so that everything opens up in a new window we've got targets equals blank and just say view recipe okay so that should be our recipe component pretty much done and you can see how we're using typescript again there in our props so if we do a search now uh we did one for garlic earlier on you can see we're searching for this particular string and it's brought us back some recipes that match so these are the recipe components that we've got you can see we've got the list items for all of the ingredients and we've got the title and the image and that placeholder is occurring if the recipe doesn't have a thumbnail so that's pretty much the app completed all we need to do really now is to style it so let's just do that quickly to finish off as i say the styling wasn't really the main point of this tutorial so we're just going to skip through really quickly so we don't need any of this here that's all of our styling gun okay so for the main app class that we've got uh let's just first of all start off by a bit of padding uh on the top and bottom and left and right and then we're going to target the search form input and i'm going to put a border on that of two pixels solid and we'll start with a blue color and let's see if we can we'll give something a bit more purpley maybe and padding 10 pixels and we'll set the font size to 18 pixels okay now the search form uh button so let's just add some similar styling to that so the background color we're going to use that same rgb color for the purpley color and also we'll just set the color of the text to white bit of padding font size is 18 pixels 18 pixels and let's remove any border okay and let's move on to the recipes uh container so first of all i'm going to put a bit of margin on the top and bottom just to push it away from the rest of the content above it and then we'll say the display is flex and the flex wrap is wrap i think that should be recipe container actually so yeah there we go it's all appearing on row's name so for the individual recipe components let's set a static width and height and if they do have lots of ingredients i will set the overflow y to scroll put a bit of padding inside of it 25 pixels and we'll just set a background color of a sort of gray color let's probably want it quite light and i'm going to absolutely position the link to view the recipe as well so let's just make sure that the recipe's positioning is relative okay and just for a bit of interest just to distinguish between each actual card for all of the odd childs we'll just change the background color slightly maybe make it a bit lighter okay so let's target that anchor tag inside of the recipe and we'll just remove any uh text decoration we'll set the background color again to the purpley color and color for that can be text color can be white so position this time is going to be absolute so we can put it in the top right hand corner so top is zero right is zero and just make sure it's got a bit of padding as well okay so the next thing we want to target is the title class that's at the top of the recipe card which had a few things in that had the image and also the title so we'll set the font size to 18 pixels margin top is just 10 pixels as well actually just go a bit more just to push it down a little bit let's have a bold font weight and also let's just display that in as a row so flex and we'll align the items as flex start so that they appear nicely side by side okay so with the image inside of the title so recipe title image let's just put a bit of margin right just so that they're not right next to each other okay so the final thing to do is to target the unordered list uh so first of all list style type none remove the bullet points uh we'll say the display is flex just make things appear in a row flat flex wrap is wrap and a bit of margin on the top and just remove everything else and zero padding as well okay so they're appearing as we would expect there now the list item elements which we can just then target as well to add some styling to them so five pixels top and right and then remove it on the left and bottom give it a bit of padding and the background color we'll use the actual purple color but let's just put a bit of opacity on there just so that it doesn't overpower the user interface so to speak and the color again can be white for the text okay so that was a just a quick whip through the styling as i said the main focus that i wanted to go through today was using typescript and hopefully you've seen how that can be used within your react code so let's have a look at our final completed project so hopefully it should be working okay for any particular search that we do um so yeah it's returning the correct uh information and all of the ingredients are there and you've got the thumbnail and we should be able to go to the url to the recipe to actually view that as well okay so that seems to be working okay so just quick review of the code so the main things we did uh in this tutorial is to actually type data that's going into functions and the data that we were using inside of functions we also looked at how to cast different types of data when we actually know that this is the type of data that it should represent kind of forcing typescript into using a particular data type when we know that the data type should be used and then we also created our own custom data type and specified its own properties which made it really easy to use within the rest of our app for example the intellisense and the type safety that it brings when we try and use the component and pass it down into sub components as props as well so hopefully you found the tutorial useful uh check out the code on github and feel free to ask any questions in the comments below if you're stuck with anything just before you go if you do have a second don't forget to subscribe to support the channel and as always thanks very much for watching and i'll see you next time
Info
Channel: Junior Developer Central
Views: 2,987
Rating: 4.9574466 out of 5
Keywords: React typescript, using typescript, using typescript with react, typescript react, react, typescript cast, typescript form elements, typescript, recipe api, strongly typed data, create-react-app typescript, create-react-app, recipe search app, junior developer central, react tutorial, web development, javascript tutorial
Id: Kff25n75jqA
Channel Id: undefined
Length: 32min 6sec (1926 seconds)
Published: Tue Mar 23 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.