Shopify Hydrogen: How to Create a Headless eCommerce Storefront with React | Christopher Dodd | Skillshare
Search

Playback Speed


1.0x


  • 0.5x
  • 0.75x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 1.75x
  • 2x

Shopify Hydrogen: How to Create a Headless eCommerce Storefront with React

teacher avatar Christopher Dodd, Web Developer / Educator

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

    • 1.

      Introduction

      1:14

    • 2.

      Key Concepts

      1:49

    • 3.

      React

      21:54

    • 4.

      Storefront API

      16:46

    • 5.

      The Shopify Hydrogen Framework

      6:32

    • 6.

      Getting Started with Hydrogen

      17:03

    • 7.

      Creating a Layout Component

      9:40

    • 8.

      Building a Catalog Page

      27:34

    • 9.

      Building a Collection page

      11:02

    • 10.

      Building a Product page

      39:10

    • 11.

      Cart Functionality pt. 1

      22:13

    • 12.

      Cart Functionality pt. 2

      18:57

    • 13.

      Deploying our Custom Storefront

      15:53

    • 14.

      Bonus: Adding a Blog section

      27:10

    • 15.

      Conclusion & Class Project

      0:42

  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

723

Students

2

Projects

About This Class

In mid-2022, Shopify launched a new sales channel on the Shopify platform, allowing merchants to host a React project on their Shopify store. This new Hydrogen sales channel, paired with the Hydrogen framework of React hooks, components and utilities built specifically for Shopify storefronts offers a brand-new way of customizing the online store experience for customers.

In this class, we’re going to go through the Shopify Hydrogen framework, learn about the surrounding key concepts, build our own simple storefront using the system and show you how to install your new app to your Shopify store.

Meet Your Teacher

Teacher Profile Image

Christopher Dodd

Web Developer / Educator

Top Teacher

Christopher Dodd is a self-taught web developer, YouTuber and blogger with a mission to help individuals learn the skills to freelance and make a living independently.

Chris learned web development in 2015 in order to work remotely and travel the world and has done so for the past 8 years.

Through his YouTube channel, blog and Instagram, Chris inspires and educates newbie 'digital nomads' to chase their passions and pursue a location independent career.

See full profile

Level: Advanced

Class Ratings

Expectations Met?
    Exceeded!
  • 0%
  • Yes
  • 0%
  • Somewhat
  • 0%
  • Not really
  • 0%

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. Introduction: Hello, students and welcome to this class on Shopify Hydrogen. Shopify's React-based framework for building custom storefronts. I'm Christopher Dodd. I'm a freelance web developer and top teacher here on skillshare.com. Having specialized in front-end web development on the Shopify platform for the last three to four years, I've spent a lot of time customizing storefronts with one of these, a Shopify theme. But in mid-2022, Shopify launched a new sales channel on the Shopify platform, allowing merchants to host a React project on their Shopify store. This new Hydrogen sales channel paired with the Hydrogen framework of React Hooks, components and utilities built specifically for Shopify storefronts offers a brand new way of customizing the online store experience for customers and a new way of developing for developers. In today's class, we're going to go through the Shopify Hydrogen framework, learn about the key surrounding concepts, build our own simple storefront using the system. I'll show you how you can install your new app to the Shopify store. For those of you who are ready to learn this next generation paradigm for building storefronts on Shopify, click on the next video and I'll see you on the other side. 2. Key Concepts: Before we get started building our own Hydrogen storefront, it's important that we gain an understanding of a bunch of key concepts that all come into play when building a custom storefront using Hydrogen. First of all, when I say Hydrogen, I could be referring to two things. Most of the time I'll be talking about the Hydrogen React framework. But when we actually start to deploy our Hydrogen app to our store, the name of the sales channel on Shopify is also called Hydrogen. Technically the name of the hosting solution that Shopify provides for Hydrogen storefronts is called Oxygen, but it shows up on the Shopify admin as Hydrogen for whatever reason. So keep that in mind. As for the Shopify Hydrogen framework itself, it's designed to sit on top of an existing technology called React. Some of you might be familiar and/or skilled in React already, but regardless, we're going to briefly go over React in the following video. It's definitely not going to be a deep dive into React in this course, but it's important to understand the basics of React in order to use Hydrogen. The other aspect which is also important to understand is how we're going to retrieve data from the Shopify back-end. This is done through what's called the Storefront API, an API that Shopify provides for retrieval of data relating to customer-facing experiences. The API is what's called a GraphQL API, which means that instead of hitting different endpoints to get different bits of data, there is a single API endpoint that our project will connect to and will request the specific data that we require via what's called a query, which looks a little bit like this. These concepts alone could be a whole other course. So in the next two videos we'll take a look at each individually and then I'll talk a little bit about the Hydrogen set of hooks, components, and utilities that play into this setup. 3. React: In this very important lesson, we're going to go over some of the basics of react. If you are already experienced with reacts, you can feel free to skip this video. But for the rest of you, let me just say that you shouldn't need to do a full course on react in order to work with hydrogen. Before I picked up hydrogen development, I had studied a little bit of react over a few years, but it's not something I'm particularly expert in at this point in time and yet I was still able to pick up hydrogen development pretty easily. No, you don't need to be inexperienced react developer to build hydrogen storefronts. But if you have little idea when it comes to react, definitely listen up to what I'm about to tell you. React. What is it? React is a JavaScript library for building user interfaces, but it's often referred to as a framework because it is a legitimate alternative to JavaScript frameworks like Angular or view, two very popular frameworks you may or may not have heard of before. You may be wondering what the difference is between a library and a framework. Basically, I'd say that frameworks are way more opinionated. They force you to build apps in certain ways. Whereas a library, you can just import whatever modules you like and just use them however you need. Let's take react, for example. Here's an example of how simple react can be. I've got a reacts playground open here at playcode.io/react. This is just an online IDE for testing out some reacts code. All I did was go to this address and now I've got a basic React app. I've got my index.html file here, which essentially just brings in the index.jsx file through the script tags. Then that plugs into this root div here. If we look at our index.jsx, you can see here we're using create route on react DOM to plug into that route element and render our app, which is right here. A few things I want to draw your attention to here. You can see here what packages we're using. You can see here we're using react and react DOM. That's important to note here because react is a library that can be used on a range of different applications. It doesn't necessarily have to be a front-end web development thing. It doesn't have to be a web app or website. It could also be a native phone app. In the case of React Native. That's why react is it stand-alone package, but then you can use something called react DOM. That is what you use to create web apps and websites. It applies all the core functionality of react with the environment of our front-end web development. The first thing you'll note is at the start of virtually all these JSX files is import statements. As I said, react is very modular and so all we need to do in order to use it is to make sure we're importing it. In both of these files, you'll see that you import react from react. That might sound obvious here, but where this is looking up is inside your node modules, see here. You can't really see it in this file browser here. But when you install react on your computer and create a package.json file, you'll see that it will also create a node modules folder, which will install all your node modules. We'll see that a little bit later if you're not familiar with creating JavaScript or node-based projects. First things first we're going to import react. Then a common pattern you'll see is we're going to create a functional component right here. You'll see it starts off as a function and then we return this HTML-looking stuff. Now, what is this HTML stuff? This is actually called JSX. It looks like HTML, but it's not actually HTML. What is happening is this is getting compiled into HTML and rendering on the screen here. You can see here we've got an H1 Hello React and start editing to see some magic happen. This looks exactly like HTML, and it's producing HTML over here. But this is not HTML. Let's take a quick pause on JSX because it is important and cover some things with JSX. What I'll do and there's enough for the app. But just to demonstrate JSX, I'm just going to create another JSX file here. We can call it script.jsx. I want to show you a few things. Specifically, I want to show you some stuff where JSX differs from the syntax of HTML. It looks very similar as I said, but it's not the same thing. Here's some differences. One of the differences is that there's no hyphens in JavaScript. If we say for instance, I'm just going to paste in some SVG code here. You can see here it's not very common, but on some HTML elements you might have a dash in-between two words for an attribute name. Now, this is not going to work in JSX. When you see anything like this, all you need to do is convert it to camelCase. I'm going to just remove the dash and capitalize width. Now if we run this, I don't know if we can run our standalone JSX, let me just copy that into our app here. If I put that onto here, you can see it works. But if we were to use a hyphen, we're going to get invalid DOM property. Did you mean this? That's because we can't have dashes in attribute names in JSX. That's one difference. The other difference you'll see right here, instead of using class, we have to use className again in this camelCase format. The reason why, is class is a reserved keyword in JavaScript. We can't use class here. That's one other difference. The third difference is if we go back here, you can see we've got some numbers here. We can put JavaScript expressions into these attributes in JSX. If I were to take away this, it's 100 right now. Actually, we want to see this rendering on our screen. Probably not a good idea to put that as a separate file. Let's just put this back in here so we can actually see it rendering on our screen. Indent a little bit here. We can actually put some JavaScript expressions in here. What we can do is instead of 100, other really simple one for you will put in some brackets here. What is 100? Is 50 times by 2. Here you can see you get the same result. We can put a JavaScript expression here. Obviously, we can put in a variable for this. If I was to go const x equals 50 times 2, and then we can just slot x in here. Then if I was to times it by 4, you can see our circle. Is it getting bigger? The height should be getting bigger, but we need to maybe create a bigger width too. Not sure what's going on there. But you can see if we check that code, if I inspect it, you will see that the result that comes through. It's a little bit tight here. Here we go. You'll see that the result that comes through is indeed 500 for the height, which is 5 times 10. We're going to see this quite often in this class. When we're using React, we're going to put through JavaScript expressions and variables into attributes, into props. That is one difference compared to HTML when we're comparing it to JSX. Another thing I wanted to demonstrate in this video was how this JSX code ends up being compiled into React functions that then generate the HTML. It's not particularly important, but I like you guys to understand what's going on behind the scenes. Unfortunately, I can't show you in this environment. Maybe later in the class when we put this project or our own project into a local host. But if we go over to JSX in-depth, on the React documentation, you can see if we learn more about it, what's actually happening is this code right here will be compiled into React.createElement, and then you'll see all of this code. What we can do if we wanted to is instead of using JSX, we could write code like this. That way we don't need to compile JSX. But obviously, this is much nicer than writing out a bunch of React methods like this, and especially when you do nesting. If we nest it a whole bunch of elements within elements, this would become super messy and almost impossible to work with. It's very handy to use JSX. But I just wanted to make note that this is not actually what makes it to your browser. This is what makes it to your browser, and that is what creates these elements in your React environment. You can also read about introducing JSX here. You can learn all about JSX on the official React documentation. Again, I encourage you to do this as we saw, JSX is an expression too. This is going to show us how we can insert values within our JSX, specifying attributes, we can use variables and other data rather than just putting it in as a string rather as we would in HTML. Zooming out from JSX now to talk more about React in general, I'll remove that variable because we're not using it anymore. We talked about the inputs before. We're going to be importing React as we need in both of these JSX files. But then in order to create the virtual DOM, we're going to use React DOM here. In our particular projects using hydrogen, we don't need to use React DOM. I believe that's taken care of by hydrogen for us. But as you can see here, we're always going to be importing stuff from React or from another React library, which for this class is going to be React. Then, you're going to see us import stuff from hydrogen. Then what you got is your exports. As you can see here, I'm importing React and then I'm exporting this functional component. Now, why am I exporting it? Well, I'm actually using it in this index.jsx file. You can see here that I'm importing that app component from that app file. If I'm using it in this file, then I don't need to export it. But if I want to use it in a different file then I'm going to need to export it. Now if I just do export without putting default after it. I can export multiple different ones here. I need to specify which one I am importing, and putting these curly brackets on either side. These curly brackets here are doing what's called destructuring. If I'm exporting multiple components within one file, which even if I only export one here, I'm not saying default. Therefore, I have to go in here and pull that out in between these curly braces. To show you the difference, if I just go over here and because we've only got one export, I can just put default here. Then inside here, I can remove these, and it works the same way. But if I wanted to say, for instance, create another component in here, then I can't just do default. Let's just say I create an app2, and then so, whoops, wrong tab. I go over here and then I can do app2. I can import multiple from the one file. But if you're just exporting one, then feel free to remove these, let's just get rid of this one now, and then put default here. That's important to note. You'll see defaults and not default used. You'll see the curly brackets and curly brackets not being used. That's why sometimes you're destructuring and sometimes you aren't destructuring. That's the imports and exports. Obviously, we saw inside this return here is JSX. If I was to create another function like I saw before, let's remove that default here. Let's just call this a custom button. I can gain access to the props of this custom button through the argument here. What I'm going to do is inside this return, I'm going to put in a button, same syntax as HTML because it is a HTML element. Then I'm going to just say, click me, let's say. Then up here, instead of this SVG, let's put in our custom button in Camel Case. As you can see here, we've got our little click me here. Now, maybe we want to make this field dynamic. What we can do is I can put the text in here. Then when I need to do is pull the children of the props. That's going to pull whatever is in between these two tags. I can go props, children. There you go. You can see here, click here, or click now, anything I put here is the children of this component, and so I can access it through its props. Now you won't see this usually, what you'll see is the destructuring used again. Instead of props.children, what I can do is destructure and take the children right off the props within this section right here. Instead of props.children, I'll pull children off of the props and then I can put it there. Then you can do click here. Then you could pass in some other data. I'm just going to put in an attribute here, let's just call it message, and I say, I am your message. Now we've got this prop that we can access from here, and all we have to do is pull that off as well. We're pulling off children, let's pull off message, and then I'm just going to do a simple onClick. Then let's put in a clickHandler to find my clickHandler here, clickHandler. Then I'll just do a simple alert with the message that's passed through. Now if I click here, you'll see we get an alert up here I am your message, and that is passed in through our component here. The two props, we've got our children that we can pass in, and then we can pass in whatever props we define as well. We just need to pull that off our props object up here, and then we can use it however we want in our own custom component. We went through quite a bit there, but hopefully, you guys got the gist. Again, we don't need to go through a whole class in React in order to understand enough to start working with Hydrogen. But if you are struggling, of course, you can research any of this stuff that doesn't make sense by going to the React documentation, or just searching for it on Google. Honestly, React is such a popular framework. There's so much information out there. If you have any issues, just start googling, just start looking at the documentation specifically with React, and of course, if you do that and it fails, you can always leave a comment below with anything you're struggling with. Before we move on to the other parts that you need to understand before we start working specifically with Hydrogen is, I just want to break down the three major things we're going to be importing and using from React. As you can see here, we have made components, but we can also import components from certain libraries. That's what we're going to see when we start to import components that are already created by Shopify for us on Shopify Hydrogen. You'll see that very soon. But then, of course, we can create our own components like we did just here. Another thing we're going to import from React and from Shopify Hydrogen is something called a hook. If you want to go to the documentation, there's an introduction to hooks, somewhere in here. Hooks, here we go. There's a whole section here, and you can read about hooks. Simply put, hooks allow you to use state and other React features without writing a class. That might be hard for you guys to grasp, for those of you who haven't used React for a while. But as you can see here, we can import a common hook called useSate from React. Let's actually look at this example. If I go into here, you can combine destructuring with the total object itself. Here we go. I'm just going to grab useState, and so now I'm importing that Hook from React. What we can do is again destructure, we can grab the state variable and then the function that sets it, and then grab that from useState passing in a default value of zero. Let's just grab this part first. Now inside our component, we can grab a count and a setCount method. That's all we need in order to create this button. I replace my button with this one right here. Now as we're clicking this, the count is going up, but you can't see it, so what I'm going to do is put in here the count. I'm just going to put it straight in the button, not put it in another element, and if I click this, the count goes up. I just want to introduce the concept of a hook very early on in this class, because we're going to use certain hooks within Shopify Hydrogen. The most common of which is the useShopQuery, which is what we're going to use to bring in data from our Shopify Storefront API and use it in our project. We've seen components here, and we've seen hooks. The only other thing is utilities, which is basically any other functions that we will use to make our life easier when building storefronts. I'll give an example, I found this utility somewhere online. It's just a function for formatting currency. We have this utility in Shopify Hydrogen already, so we shouldn't need to use something like this. But as you can see here, we can grab this utility. Let's just paste it right into our code here. I'm going to get rid of this component code. This is written in TypeScript, so I just need to remove the type definition there. Now you can see it works. Let's just say if we were to do a price. Again, I can throw in an expression here, and let's just say formatCurrency and throw in 110.10. Now you can see here because we are using the currency USD and the style of currency, you can see now that currency gets formatted nicely. If we were to add some extra decimal points here, it still gets rounded up to the nearest cents here, and then we put the $ sign in front. If we were to make this something like Great British Pounds, for instance, you can see that it's now the pound symbol instead. This is what a utility will do. It's just a function that makes our life easier. As you can see here we've imported it or just grabbed it. We could, of course, create a new file, and then export it, and then use it wherever in our project, which would be the more likely scenario. But I just wanted to demonstrate what a utility is, because we might use some utility functions in our Shopify Hydrogen storefront as well. That's really it, guys. You can, of course, go way deep into React, but for this course, that's all we really need to get started. All of these concepts we just discussed are going to help us generate the UI for our new custom storefront app. But the other side of this is going to be how we actually connect this UI to the storefront API. This is exactly what we're going to cover in the next video. 4. Storefront API: In this lesson, we're going to talk about the storefront API, which is what we would use for retrieving the data required to populate our storefront with all the product, page and blog post information we want to show to the user. To provide a little context here, the Shopify API is one of the few APIs provided by Shopify. The two most common, I'd say, are the storefront API and the Admin API. The Admin API is what you would use to complete admin functions. Whereas the storefront API is the API for retrieving customer facing information. I've talked about the storefront API in a few of my other videos, you might have seen me connect to the API and less than 11 of my Shopify theme programming class and for a minute, 1820 in my YouTube video using JavaScript in theme development. However, as I mentioned in those videos, the storefront API was not built for Shopify themes, instead, it's intended for every other scenario where you would need to access storefront data. As Shopify say in their documentation, it can be used anywhere your customers are, such as a website app or video game and now this includes Shopify hydrogen apps. How does it work in Shopify hydrogen? Well, the good news is that hydrogen has a built-in hook which helps you easily connect to and query data. It's called the use sharp query hook and later in this class we'll set up our access details in the hydrogen config file and then use the hook to pull in whatever data we need. For now, what I want to briefly cover is the syntax of GraphQL, which is the language we use to query the storefront API. This right here is called graphical. It's a graphical in-browser GraphQL IDE. That might sound super technical, but basically all this is, is a way for us to create and test out queries before we run them in an app. I'll show you how to set this up for your particular project later, but for now you can see I'm running a local server. This is actually a hydrogen project and luckily for us, one of the features is this graphiql. It's basically GraphQL with an i between the graph and the QL. Graphiql, I guess it's how you could say it. We've got this tool built-in and all we have to do is, if this is our root domain local host 3,000, we just need to put graph iQL after it, and then we get access to this little tool that allows us to run GraphQL queries to whatever storefront API hydrogen project is connected to. This one is actually connected to the hydrogen preview store. This is the standard store that will load into your storefront API configuration settings when you create your first hydrogen storefront, you can update these settings, will see that in a later video, but in this class we're just going to use the hydrogen preview store and that has a whole lot of data already in it so we don't even have to create sample data for this class, we can just use what is already provided for us from Shopify. We've got a query here already, if I click "Run" here, you can see that we get a data structure back that mimics what we write over here. I like to use indenting, so I'm just going to put this over here. What we get back is some JSON that mimics the structure of our query. That's what's cool about GraphQL, it mimics what we get back in terms of JSON. To explain this a little bit, we've just got a basic query here, we're taking the query root of sharp, and then we're opening up a selection here and then we're defining what fields we want to return. All we're doing is returning the name of the sharp, which is hydrogen. But I could also add in this field description, and then if I run that, you'll see that when our query comes back, we've got our description coming through as well, okay? We can add in whatever fields exist on the sharp object here, if I was to remove the selection altogether and try and run that, it's not going to work, it says field must have selections. There's certain fields in your API that are going to require selections and shop is one of them, so it's not going to work as requesting the whole object, we're going to have to request the specific fields within that object. How do we figure out which fields we can access on the object? Let's go to the documentation. If I simply search for storefront API in Google, I should be able to find it. Here is the page on the documentation, the graphQL storefront API from Shopify and honestly their navigation is a little bit hard to navigate but I want to go into Comment objects, go into here and if we scroll down, this is not what I'm looking for, online store is the category I'm looking for, I'm going to objects, we can see here the shop object, so we can see the shop represents a collection of general settings and information about the shop and here are the fields, so we access the name of the shop, the description, we can also get Meta fields on it. We can get the primary domain, so if I wanted to add that primary, the good thing about using this interface is it's got auto-complete. I can throw in primary domain there and it requires selections. If we wanted to use that, we just needs to check out this which is the datatype. As you can see, there's a range of selections in here too so I'll have to open up a selection on that one and then URL is one of the fields on that. I can run that and then now we can get the primary domain URL. Now, one of the trickiest things about GraphQL, this is pretty simple up until this point. But if we start to work with relational connections, we're going to start to see something called edges and nodes. What I mean by that is if we go into here and type in something that's a plural, we can't do it on a shop object, but let's go back to our query route here and if I type in collections, as you can see here, it's going to return Collection connection. Here we can target a specific collection, but if I go here and do collections, what I'm now going to need to do is use edges and nodes, alright? I'm going to have to access the edges on this collections list and then grab whatever data I want on each collection within that list of collections here under node. I can grab the, let's say the name with the handle rubber and then if I hit run here, I'll probably have to put it in the perimeter here. As it says here, you have to provide first or last, so what that means is I have to specify how many collection objects I want to return, so I can request the first 10. I run that. You can see here that I get back an object that's similar to the structure here, I get back ten collections or maximum ten collections, there's only 1, 2, 3, 4, 5, 6, I believe, collections in our store in total, so we get the first 10. If only six exists, we get six back and because we've only asked for the handle, we only get the handle back on each node. Now, this edges, node thing is a little bit confusing but you'll get used to it, the way I like to think of it is we can get more than just the edges back on a particular collection list, any list for that matter. If I go under edges here, I can also get an object here called page info, which is a selection and then I can see if it has a next page. If I go over here and run that again, not only do I get the data I'm looking for, I also get the information for pagination, which is telling me does it have a next page, it doesn't. If I set this to three, so it's only going to show me the first three and the second three and I run that again. Now, if we look down, we only get the first three results and we get true now for has next page. Similar thing with node, we can go underneath the node and we can type in something called cursor. Let's run that and see what comes back. As you can see, we've now got this little id here on every node, which gives us an address for that particular node. It might sound pretty complicated, why can't we just return a list, but it goes back to relational connections between these different resources. Because these different nodes are resources themselves and what we're doing is returning a connection to them. It's not just data within a collection. It's also product data as well that could be part of multiple collections and so it looks complicated, but all we need to remember here is even if we're not using pagination, so if I remove these, just be sure to use edges and nodes when we're handling connections in this list fashion. Before we move on to talking about the Hydrogen framework, I just wanted to show you a few more examples of what you might deal with in terms of GraphQL while you're creating custom storefronts using Hydrogen. A few examples you can find within this tutorial that is provided by Shopify, in essence, this class is a video version of this anyway, we will use a lot of what gets talked about in this tutorial, but we will also not use a ton of it as well. I'm going to try and keep it really simple. A lot of this tutorial I've found is really jumping ahead in terms of adding a lot of code, which might not make a lot of sense. The class has been designed to step through it a bit slower for you guys. But I want to draw your attention to a few GraphQL queries that you may end up using. As you can see, we've got that query that we saw before, where accessing name and description on shop, so that's a very basic query there. If I scroll down a little bit more, I'm not sure if it's on this page or on the next page. Let's go to build a collection page, scroll down. Here, you can see we've got collections here. We can actually skip out the edges part, so we can just write nodes instead of writing edges and then node singular. If I wanted to remove edges here and run that, you'll see that we get back the nodes without having to put in that word edges, so that's an option as well. Then as you can see here, we've got the parameter for gaining the first eight eight, of a particular collection, passing through a handle, which we'll see later in this class, and then we're grabbing the first variant off of each product. Again, we'll do something similar in the class. I just wanted to run through a few examples, see if there's anything theoretical that I need to tell you guys before we get started, although this is quite similar if I go into the next page. Here's something that I wanted to show you before we get started, is the use of these fragments. Fragments are like if you're used to Shopify theme development, you can think of it almost like a snippet. It's a reusable bit of code that we can plug into other parts of our GraphQL query. We define this fragment here, which tells which fields we will want on media. This whole fragment here tells us which selection of fields we want and then we can plug that in to where we need it by using this dot, dot, dot. Instead of writing out all the media fields here, we can just expand out the fragment that we created up here. That's handy when we want to reuse that selection across multiple areas of our query. The other thing over here that I want you to notice is this dot, dot, dot, and then on. Here, it looks similar in terms of you've got the three dots, but as much different in the sense that this is only going to return this selection when the type is media image. It's going to return this selection, when the media field that comes back is a media image. It's going to return this selection when it's a video. It's going to return this selection when it's a 3D model and this selection when it's an external video. I guess that's why it's created in a fragment so that we're not nesting all that code within our selection here. I'm not sure if we're going to necessarily use fragments in this class. We're going to keep it very simple. But I just thought to mention this while you're looking through examples from Shopify, outside of this class, you may be wondering what's going on here. Definitely look up GraphQL fragments if you're interested to learn more about this. Let me go down, see if there's anything else I want to share with you guys. As you can see here, guys, this tutorial throws in a lot of code really quickly, which is why I'm not following this exactly for this Skillshare class. I think they jump into certain parts a little too quick. While I don't like to be drawn out, I do like to cover a lot of the stuff in a step-by-step sequence that allows you guys to understand what's going on at each stage, so I feel like it's better to go slower and actually understand deeply what's going on rather than jump ahead so much. In my opinion, I believe that they're jumping a little bit too far ahead, especially for somebody who hasn't used React before or is new to React, this tutorial goes and jumps straight in, has a lot of detail. Obviously, a lot of this is just React code. That's the main stuff I wanted to show you guys. I wanted to show you guys if I go back to here the fragment stuff. Let me just find that on the documentation for you guys, if you want to have a look at that later. Here you can see on the GraphQL documentation, the official one at graphql.org. If we look at the section on fragments, you can go more into details here on what fragments are. That's the only complex example I've seen in the Shopify examples of GraphQL. We're probably not going to use fragments in this class, but just in case you see that on an example like on Shopify documentation and you're wondering what's going on there. But we're going to try and keep it as simple as possible and then try and expand from there. But it's important to understand GraphQL at least on a basic level, before we get stuck into creating our projects, we need to know how we're going to query the storefront API in order to get the data required to build out custom storefronts. That's why we need to do a little lesson on GraphQL. In the next video, we're going to cover the Shopify Hydrogen framework. 5. The Shopify Hydrogen Framework: In this lesson, we're now going to talk about the Hydrogen framework ie the set of hooks, components, and utilities that Shopify provides to assist us in creating custom storefronts. For most of this class, I'll be explaining Hydrogen hooks and components as we work through our own Hydrogen project. But there are a few concepts regarding Hydrogen I'd like you guys to understand before we get stuck in. Firstly, if we head to the App.server.jsx file here, you'll notice this file is going to look quite similar no matter what Hydrogen project you're looking at. You've got this renderHydrogen function right here, which is responsible for hydration. Hydration in this case is relating to server side rendering. Basically, this is the function that sets up your project as a Hydrogen app. After importing renderHydrogen up here, the other top level components you are likely to notice relate to routing and providing. In a typical React project, you might use something like React Router, which is another library for handling routing, but Hydrogen comes in with built-in routing. Using the combination of the Router component and the FileRoutes component, we can easily set up basic routing within our application that mimics the file structure of our project. For instance, in our routes folder, if I click over here, if I create a catalog. This is what we'll do in the class later on, but just to show you upfront, if I create a catalog.server.jsx file, then I can access it by typing catalog after the route domain of our application. If I run this; it's not currently running at this point in time, but if I run the command yarn dev or npm run dev, we're going to be running that on localhost 3001. I'm running another store at the moment, which is why it's at 3001 and not 3000. If I command, click that, you'll see Hello World here. If I go back into my code editor and let's just put something in catalog.server.jsx. Let's grab what we have in index.server.jsx and just replace this to Catalog and replace this here with Catalog with a capital. Hit "Save" on that. Switch back to our app in the browser. As you can see here, it's running the index route, which if we look, it's just creating a div with Hello World so that matches. Then if I go over here and after our route domain put catalog, now you can see the word catalog coming up. This is how we get built-in routing into our application. We just put in a router and wrap that in FileRoutes, and so our routing will mimic whatever we put in this routes folder. We can do nesting via nested folders. It's actually quite easy to set up nesting with Shopify Hydrogen. I can also do a dynamic value. Let's just say I had a nested route for collections. I'll create a collections folder here. Then I can also create a dynamic route. I can use handle as a variable, server.jsx, and then we're not going to do it in this video because we'll have to bring in the use shop query hook and start querying API, which we'll get into in a later video. But essentially now I'll just change this to Collection. If we did have access to the collection, we can start to dynamically take the Collection that we're looking at and maybe put out its title or something. We can create these dynamic routes as well. This will live at, let's just say our collection was called shoes, so we just go to this route, collections-shoes, and then that shoes part becomes the handle, and so it would serve us this file through that route. I can also use the routes component. It's not currently imported but we can import the route component from Shopify Hydrogen. What that allows us to do is define a route down here. This is handy for creating a catch-all route for 404 full pages for instance. If I create a NotFound component, I can load that in there. Then if the URL doesn't go through FileRoutes, it can go through this backup Route instead. We're going to see that in this class as well. Then the other components, you're going to see are the Provider components. As you can see up here, Shopify Provider is the top level provider component from Shopify Hydrogen. We put that around the router so that we have access on every page to core Shopify functions like the use shop query hook, which we'll use in virtually every route. This pattern of using a Provider component with related components and hooks is something you're likely to see in various parts of your application. Examples include the CartProvider for providing cart functionality, the ProductOptionsProvider for setting up states to track the currently selected variant and option selected on a product page and CartLineProvider, which provides easy access to data relating to an individual CartLine. These are just a few examples of some of the available components in the Shopify Hydrogen framework, the full list of which you can find here on the official Shopify documentation. Also as a tip, if you ever feel lost on what a particular component or hook does, you can simply just Google Shopify Hydrogen, followed by the name of the hook or component, and that should usually direct you to the relevant page of the Shopify Hydrogen documentation. Remember hooks generally look like this with a lowercase first letter while components all start with a capital. This is to differentiate them from regular HTML tags. 6. Getting Started with Hydrogen: Without further ado, let's actually get into building our hydrogen storefront. We've talked a lot of theory, it's time to get into the practical here. There's two ways we can get started. Number 1, you can do it how I did it which was following this documentation here, shopify.dev/custom-storefronts/hydrogen/ getting-started/quickstart. Basically, just look for this in the navigation. Here, you can see in Step 1 we can create a Hydrogen app. I was using NPM until I ran across this caching issue that forced me into using Yarn. We'll talk a little bit about that in a second. Now I use Yarn, but you can also use NPM. It's important to note here that when we're using these tools, you need to have them installed. You need to also ensure that you have the latest version of node installed as well. This is going to come up every single time we use package managers. If you're not familiar, node.js is the JavaScript runtime, we need this, this is at the core of NPM and everything we'll do in this project. Make sure you have the latest version of that. Then NPM is Node Package Manager, it sits on top of that, and it helps you to install and run node packages. We need to make sure we've got the latest versions of that. If you want to use Yarn, you can install Yarn as well. The details for installing all of these command line interface tools are on their respective websites. I'm going to show you how to do it this way first. I'm going to open up my favorite terminal application, it's called iterm. I'll maximize this for you, so you can see easier. Clear all that stuff there. I'm going to simply navigate to my desktop for this, so I'm going to cd desktop. Then let's run these commands. Let's just run NPM init, Shopify hydrogen. It says you'll need to install the following packages. Yes. Just need to give it some time to process here. Now here, it's going to give you the option to do Demo Store, or Hello World. Demo Store is a more full-featured hydrogen project. I don't recommend installing Demo Store in order to learn hydrogen, because it comes with a lot of code and a lot of setup that if you're just learning hydrogen, it's better to keep it simple. I like to go with Hello World. Then, here is a matter of preference, if you don't know what TypeScript is or don't use TypeScript, then just choose JavaScript. I'm going to call this custom storefront. Now it's going to download the code from the hydrogen repository. Now after a fair amount of time, it has finished installing. Now, I'm going to open up a new window or Visual Studio Code, and we can start to run this project. I'm going to open up a new window, will just resize it to fit your screen. Then I'll click "Open", head into our desktop, and open up that custom storefront folder. Here, if we run a terminal within this project, we can do this from within the project on Visual Studio code, or we can do it using our other terminal application. Is just easier within our code editor because we've already navigated to that folder. Now all I need to do in order to run this, is npm run dev. As you can see here, it's going to say that we're now running at localhost 3,000. I'm going to command-click to open that up. As you can see, all it says is Hello World. The reason why it says Hello World is if we go into our src folder right here, and head into our index route. Just in here in routes index, you'll see Hello World. Remember we already talked a little bit in the last video about what's going on the app.server.jsx file here, so I won't go deep into this, but this is the heart of your app right here. We've got our Shopify provider, which provides basically all the functionality that we will need for our hydrogen app. Then of course we're pulling him router and file routes, for our routing. This other component that we're importing from react, is a experimental feature in react at this point in time. If we look at the page for suspense on reacts website, you can see here that there's a lot of red here. Basically a suspense component, it allows you to wait for some code to load, and declaratively specify a loading state. This allows us to do asynchronous loading within these two tags. We could instead, and let me just do this right now instead of having a null full back, just to loading. Now what I've done to get us started so that we're not wasting time here, is I've created all the CSS for you, so that we're not writing CSS as we code through this project. I've also updated the index.server.jsx route, so that we can see the pattern that is going to happen in a lot of the routes, where we input a bunch of components and hooks, we export a particular component, and then below that, we write our query. What you can do, this is the second option, is you can get clone the storefront project, that I've uploaded to my GitHub, this is a public repository. This is basically the same thing as if you were to do what we did here in our terminal with creating a new hydrogen project, and choosing Hello World, except that I've updated this index.server.jsx file, to demonstrate the ongoing pattern that we're going to see in a lot of routes. I've also added a bunch of CSS here. I'm also going to update the branches as we go along, so you can see the end point as well. I encourage you, instead of doing it this way, I encourage you to get clone this project, run npm, install, and then let's follow along together, using the exact same project. What I'm going to do, leave that, and then I'm going to, let's just close out of this. Then in my iterm here, I'm going to navigate to my code folder, go into my Skillshare folder, which is where I put my Skillshare projects, and let's run git clone here. I'm going to go git clone, copying that URL. All I got to do is click on the screen button, and then copy the HTTPS address, and then now it's going to download that repository to my computer. Let's navigate into hydrogen class storefront. Then from here, we just run npm install, to install all our node modules. This is something that's happening automatically when we run that previous command of npm init Shopify hydrogen. It runs npm install for you. When we're downloading a GitHub repository that said node project, it's going to get ignore the node modules file, because that's not code that's specific to this project, and it just stores the references in the package.json file. Then when you run npm install, it will then install all the dependencies. Just a bit of extra context there for those guys who aren't too familiar with node projects. There we go, we've installed our dependencies. Now, I'm going to open up Visual Studio Code again. Get this to our screen size for you guys. Then I'm going to open up that folder. Going into code, Skillshare, hydrogen class storefront. Removing that tab there. You can see if we go into the SRC folder, in index.css, we've got all the CSS that I've already written for this project and then if we go into our index.server.jsx route, we've got this right here. Let's go ahead and run a new terminal directly inside our project. We're going to clear all of this annoying code that comes up. That's just a me thing. Don't worry about that. Then let's run our command for running the server, npm run dev, and then we will open up localhost:3000. I'll get rid of these other tabs. Now that we already got our project locally, and here you can see we have a title and a description. Now, where's that coming from? I wanted to update the index.server.jsx file to show you a pattern that we're going to be using throughout virtually all of our routes. How we're going to run through this project is we're going to create a section at a time. We're going to do the catalog page. we're going to do the collection page. We're going to do the product page, and then we're going to enable code functionality. Basically, the pattern that we're going to use, and if you can understand this within Shopify how to do development, then you're well on your way to coding any type of project. The pattern is this. We're going to import what we need from Shopify hydrogen, we're going to export a component, and then we're going to create our query. Now this is out of order because we're using the query up here in our useShopQuery hook. But for whatever reason in the examples, Shopify puts the definition of their query at the end, so I'm going to follow that sequence. I'm just going to minimize that for a second. Hold on, that maximized it. Let me see if I can just create some more space here so that we can, no, that creates a new tab. Maybe what I'll do is I will put that away for a period because I want you to look at what's going on here in its entirety. Let's remove that so we can get a closer look. What's happening here is if you remember in the previous index.server.jsx, it just had a simple component that had a div with hello world in it. Now that's not going to be particularly useful because that is not dynamic content at all. But what we're going to be doing in this class is we're going to be bringing in dynamic content from your store. I'm not going to reload the page here because I already shut it down, but here, you can see we've got hydrogen and then we've got a custom storefront powered by hydrogen, Shopify's react-based framework for building headless. Where does that come from? Because if we look inside here, you can see that these are both dynamic values. What we're actually doing is we're pulling that information from the storefront API. The three things that we import from Shopify hydrogen here is the all-important useShopQuery hook, which is what we use to query the storefront API. We're bringing in this object here called CacheLong. This is just a caching strategy so there's nothing too complex going on here. We can easily replace this by writing out the caching strategy. It just helps us a little bit saving time by bringing that little utility out of hydrogen. Then this right here is a utility that helps us to do syntax highlighting with our GraphQL queries although it doesn't really look like it's working in my particular setup, but that's fine. We don't really necessarily need that, that's just a nice to have. What we're doing here, so we've got our home component right here that runs on the index route, and in our return statement here, we're returning JSX which we saw earlier in the theory. I've already set up a class here. Again, this is not going to be a CSS course so I'm going to just put in class names that match up with the CSS that I've built so that we can get some styling from the get-go. All we need to do is make that match up with our CSS file here. But again, you can totally edit this to however you want. I just didn't want to get caught up on any CSS in this class because this is not a CSS class. Getting back to our index.server.jsx file here, what we're doing is we're passing through an object to useShopQuery with our GraphQL query allocation strategy and then we're saying preload: true. This is just a basic default setup that you can see in the Shopify examples. The main thing to understand here is that we're writing our query here in GraphQL and then we're putting it into useShopQuery. Now in the examples, what you'll see is object destructuring happening right here. It doesn't have this line, but I like to break it out, or at least for this class because it just makes it a little less complicated. You can break down the steps a little bit. What we're doing is the data that's going to be returned from the API is going to go into this data object here and then we're going to destructure it in order to get the returned data. Now, here's something you can do throughout this class that will help you determine what comes back from the API. You can go console.log (data). Now, where do we find this information? Well, we're actually on a server-side component here. As you can see over here, I don't believe we have any client-side components just yet, but as you can see here, all of our components so far have.server in them. If we run this, the console log is going to happen in our terminal but not in our browser. Let's open up our terminal again, get rid of all that, and then let's run npm run dev. Now we're just going to have to hit this. I'm going to refresh the page and if we go back to our console here, I'm going to open this up and you can see the data that comes back. It's actually coming back twice here. You can see we get this data object and inside we get the sharp object, and then inside that we get the name and the description. This will allow us to inspect what's inside. As you can see, this destructuring matches what comes back from that data object. We can remove this and instead of having Shop here, we can do data. data. shop. Refresh the page and you see we get the same result. But obviously, that's a little bit uglier. This might look a little bit more complicated, but it helps us to pull off that sharp objects so that we don't need to put data, data in front of it. That's essentially what's happening there. I remove that console log and you can see that we're pulling off the shop object off of the return to data and then we can then access the name and the description because that's what we requested in our GraphQL query. That's the basis of everything we're going to be doing in this class, we're going to be importing components, hooks utilities from the hydrogen framework. We're going to be using those hooks to plug into some data. We're going to be using that data here in our components, and if it requires it, we're going to write queries that we will plug into in the case of useShop query in order to get our data. If you understand this pattern, then we're well on our way to coding up our first-ever hydrogen storefront. 7. Creating a Layout Component: In the last lesson we got started with our project, we got it set up and running on our computer. You can see here. One of the things I forgot to mention in the last video is that this data is coming from the Shopify preview store. If we go into our explorer here, and go down to, I believe it's hydrogen.config.js, you can see the storeDomain is hydrogen-preview.myshopify.com, and the storefrontToken is what we need in order to connect to that. That's why we've got this data right out of the gate. In this class, we don't actually need to create a store or update our store with demo data because we can just use this demo store the entirety of this class. However, when we deploy this to our actual Shopify store, we're going to want to replace these details with our own store domain and our own storefront access token, okay? I just thought I'd mention that before we get started. Some of you might be wondering, where are we getting this information from? Well, it's pre-loaded to use the hydrogen preview store, which I think is very nice in this class. For instance, we don't want to have to create all this demo data, we can just plug in to existing demo data which is very convenient. With that out of the way, what I want to do in this video is create a layout component. Our layout component is going to wrap around our entire website and basically provide a header and necessary SEO that will run on every route in our hydrogen storefront. What I'm going to do is, I'm going to go into the SRC folder here, create a new folder for my components, and then inside this components folder, I'm going to create a layout.server.jsx component, okay? Now, this component is going to serve two functions; it's going to render a header, and also render SEO information so that any page on our website has SEO already built in, okay? Let's just, to make our lives easier, I'll just copy everything in here and put it over here, okay? Now what I'm going to do is, remove that, and let's just put a div in here to start with so that we don't get an error, and then we'll name this not home, but layout. Then as I showed you in the theory video, I'm going to use object destructuring to grab any children that get passed into this layout component, okay? Same query here, we're going to use the name and description for the header and also the SEO information. Then what I'm going to do is in our index.server.js file is simplified as a ton, we're not going to use this data on our homepage, so I can remove all of this, I can remove this up here, and we're just going to return a very basic component, and in here, I'm going to just put homepage, okay? Get rid of that. Then what I'm going to do is bring in that layout component. I can import, and I believe we're exporting default over here, so we don't need to use the curly brackets, we can just do layout from components, and then we just go to create a path to the layout component. Then what I want to do is pass in all of this in between our new layout component tags, okay? Now, as you see here, we are accessing the children, what I want to do here is put that children in between these divs, okay? Let's see if that is working now for us. If I go over here, you can see, yes, there are no errors, okay? Going back to here, what we want to wrap around this basic homepage is a header and SEO information. Let's start working on what's inside our return statement here, our JSX. First of all I do want to return whatever gets passed through those layout tags. What I'm going to do is call this main because this is going to be our main part of our page, and then I'm going to wrap children in a couple of suspense tags because we don't know what sort data could be coming through. Remember this is going to wrap around every route, not just the index.server.jsx route, okay? Now, we're going to get this error here and that's because we haven't imported suspense yet. I'm going to import suspense from react. As you can see, it just filled that out for us. Now we are bringing in any children whether they're loaded asynchronously or not, okay? Now all we got to do is bring in our SEO and our header. Now, the way we do SEO in Shopify hydrogen is to simply import an SEO component from the hydrogen framework, and then what we can do is bring in that SEO component over here. We don't need an end tag, but we do need to put it in that dash to close it. Then inside here, we'll put in the type of default SEO. Then in the data field, we'll put in an object for title and description, and this is where we'll use the shop name and description that came back from the storefront API. We can put that in here, shop name and shop description. Now, what you'll notice here after we've done this is that we're getting all these red squiggly lines, and that's because we can't return multiple elements on the top level with JSX, so we're just going to have to create a top-level element, and we can create one of these blank ones, like this, little bit of a hack, but now we don't get those red squiggly lines. If I go back here, re-run our homepage, and I open up my dev tools. I just pressed Option Command I to do that, otherwise you'll have to go into your menu and open up DevTools. I do this in every class, so hopefully you guys are following me here. Then if I go into our elements here, you can see that if we go into our head tag here, you can see that we've got our title and description coming through in these meta properties, which is our SEO tags, okay? We got our SEO coming across now. Now we just want to build a header. Again, I'm going to leverage some of the classes I've already written in the CSS, this is not a CSS class so I'm going to grab this container header-inner as a class. Then in here I'm going to create a link so we can use the link component in Shopify, and I'm going to link that to the homepage by just putting in slash there. This link is going to be basically the header logo, it's a common pattern with headers that if you click the logo, it will direct you back to the homepage, so that's exactly what we're doing here. Then in here is where I will put the shop name, okay? Now we need to import link from our hydrogen framework because we haven't done that yet. Then if I hit "Save" on that refresh over here, you can see we've got this header now. Then if I click on this, it'll take us to the homepage which we're already on, okay? That's going to come in handy later. Now what I'm going to put in is a unordered list with the class of header navigation. This is going to house our header navigation obviously. Then I'm going to use some Emmet here to put in three links. Just going to have empty links in this stage, link 1, link 2, because we haven't got any other pages, so I'm just going to put in some placeholders basically. Then finally we're going to have a spot here to link to the cart page. We don't have that yet, so what I'm going to do is just put in a placeholder here. The class name of it is going to be header-cart-link, so I'll just put that in there, okay? I'll hit "Save" on that. If we go over here, you can see we've got our header and everything is nice and centered. Basically, what we're going to do guys is as we go throughout the class, we're going to update our header as we go. As we create new pages, we can add in links to those pages here, and then we can add in our cart icon here with the number of items in our cart as well. We'll get to that later in the class. But now that we've created this layout component, you're going to wrap all your routes with this layout component tag here, and that will ensure that the header and SEO information will appear on every route. With that out of the way, let's actually create a catalog page for viewing all of our products on our Shopify hydrogen storefront. 8. Building a Catalog Page: In the last video, we created this layout component, which is what we're going to use as our standard layout across all our routes. We updated our index route and now we have our super basic homepage sitting within our layout, which then gives us our header and our SEO, which we saw in the last video. In this video, what we're going to do is create a new route. I'm going to call this the catalog routes, sorry, that's the wrong folder, right here in our routes folder, catalog.server.jsx. Just as a little bit of context here, the reason why it's a.server.jsx file here is because we're going to be querying the storefront API. It's a good idea to every time you query the storefront API in every router component, that you're doing that. You want to be doing that as a server-based or server-side component, that way we're not exposing what we're querying, essentially database, to the end user. Let's start off by exporting a functional component here. This is going to be our catalog page, which is going to house all of the products that exist on our store. I'm then going to put in a return statement right here and then we're, of course, going to start with the layout component. We're going to have to import that, otherwise, we're going to get an error. So import layout from navigate to the path, to our layout. Just so you know, guys, this dot-dot means go back one in the SRC folder, and then we can look in components and then find layout. If you're not familiar with this right here, that's what that means. We're going to be drawing in some asynchronous content here, so I'm going to put in a suspense right after my layout. We're going to have to import suspense from React as well. Then a little bit of structure here that I've already set up, I've created some CSS for the classes of catalog page and container. We're just going to put our page in a nice container. Then we're going to create a div with the class of products grid and that's going to house all of our little product grid items. If I hit "Save" on that, we're currently not pulling in any data, but if I go over here to the catalog page, we've got a pretty much blank page. If we go and inspect this, you will see, however, that we've got those divs that we set up, the catalog page, and the product grid. This is basically useless until we bring in some data. Let's write our query down below here. I'm going to create a constant called query and then I'm going to use GQL string template and put in our query here. Because I am using this, I'm going to have to import that from Hydrogen, so I'm going to do that up here. Import GQL from Shopify Hydrogen. Actually, let's do this in our graphical interface. Then once we've tested it, know that it works, we can bring it into our project. I think that's a bit nicer. I'm going to go to graphical here. We can close down our DevTools. I'm going to get rid of this standard query right here, open this up. Then what I'm going to do is we can name our query first up. It's a good convention to do that, so I'm just going to create a named query. I'm going to call it query products. Then here is where we actually start to request some data. I'm going to request products. It's going to error unless I determine how many I want. I'm going to ask for the first nine. Then I'm going to open up a selection in here and I'm going to grab all the nodes and the items that I want on it. Let's start with title and handle. Let's run that. It says query does not exist on type query route. That's because I've got to move this. I shouldn't be nesting that in a object there. As you can see, now it looks a lot nicer, there is syntax highlighting, so I think we have solved that issue. Let's just find out. There we have it. We are able to get back the first nine products from the store that we're accessing, which is just the Hydrogen preview store, and we can get back the title and handle of all these products. Let's start with that. Let's move this back into our project. Try and indent it nicely here, like that. Then we need to bring in use sharp query. We're importing that from Hydrogen, of course. Then we want to go inside our component here. We can basically just copy the same, but use sharp query. Now we do over here. From the layout.server.jsx file, put it in here. Instead of sharp query, it's just going to be query. We can name this whatever we want. We could name this catalog query, but I'll just call it query for now. Then what I'm going to do is let's just console log the data that comes back so we know how to D-structure it. Let's have a look here. We've got a bit of an error. CacheLong is not defined, so we need to make sure that we're importing that from Shopify Hydrogen as well. CacheLong. Let's see if this works now. Let's go back. Open up localhost 3,000 in a new tab and let's open up our dev tools again to see if there's any client-side errors. We got an error here. It says failed to connect to the storefront API. This might be due to my Internet connection. I forgot to put a C there, so that's probably what the issue is. Let's refresh over here. Now we just need to go into the catalog route, and now there are no errors. There is some error here. But before we saw that error, you can see here, might be a little bit hard to see, but we are actually console logging out the data object that comes back from use sharp query. You can see here, we can use this as our format for D-structuring, we can grab nodes within products within data here. I'm going to do that. Let me push this up again so we can copy what we have here. Just like we did here when we D-structured and we got to that sharp objects, what we can do here, if I copy that, we're going to go into data once again, but then instead of sharp we're going to go into products. Then within products will pull off nodes. Then if I run nodes as my console log here, let's refresh our catalog page, then if I look in here you can see all the nodes returning. These are our products. You can see it's returning a few times, but you can see an array of nodes. We're getting back the title and the handle of each of these products. Then what we can do is we can use that in here. I could go nodes. Here's where instead of running a loop, what we're going to do is run map. I'll explain why we do that in just a second. We're going to run map. Then what we're going to do is pass through each product through some JSX. I'm just going to put in a basic div here and then what I can do is throw in a JavaScript expression into this JSX. I can do the product title right here. Actually, what we'll do is let's make this a list, so I'll make an unordered lists. This is not going to be the final form, but it'll just look nicer for this basic example. Then I'll hit "Enter" on that. There is a syntax error here. I believe we need another bracket there. Sometimes when there's a syntax error it will stop your server completely, so we need to rerun the server, npm run dev. Now if we go to our catalog page, you'll see that we have an unordered list with all of our different products. Well, at least the first nine of them, which is what we requested right here. Now to explain this map thing here, basically, we want to return all the nodes, but we need to wrap each of these nodes in some JSX, hence why we're using map. If we just did nodes by itself without any JSX, let's see if that returns anything. We can't just return a random array. We need to actually convert that array into JSX, so that's why we're using map here, which basically is going to create an array of JSX. That expression will be inserted in between these unordered list tags. Hopefully, that explains the use of the map function there in JavaScript. We've got a basic list of all our product titles below. The first nine, at least, at the moment. But what we want to do is expand upon that. Showcase the price, showcase the image in a nice little grid as you would expect on any e-commerce site. What we're going to do is create a component for this product grid item. What I'm going to do is go into my components file here and create, I'm going to call it, ProductGridItem.server.jsx. Then what I'm going to do is the usual export, a default function, and so our component. I'm going to simplify it inside the actual component itself and call it ProductCard. Then obviously we need a return statement for the JSX. Let's just be very simple for the time being and move this list item into our component here. Now we're going to try and access product, which means we need to parse that in as a prop. I'm going to pull the product object off the prop of this component, and then on this side, we need to import this ProductGridItem or ProductCard, as we've called it here. I'm going to first type it out here, ProductCard and hit "Save" on that. Sometimes it imports it automatically for you, but it looks like we're going to have to do it ourselves this time. I'm going to import that ProductCard. As you can see, the rest was filled out for us, which is very nice. Let's try and rearrange this a bit nicer. I'll put my components that I create myself after my imports from react and hydrogen like this. Then what we're going to do is create a prop called product and parse in that product objects. Now if we go over here and refresh, you'll see we get the exact same result. Now we're just encapsulating this code into its own component. Of course, we need to export that and then import it up here and then we can use it down here, parsing in each product into its props. There's a lot of stuff we're going to do inside this ProductCard. Let's remove this UL because we're going to create this as a grid, not as a list. So I'm going to get rid of that UL component, update the nesting, and then over here what I'm going to do is create a div with the class of product-grid-item, which again, this is existing CSS that matches what I've created in here. Then what I want to do once I'm inside here is obviously bring in the title, but I also want to bring in the image and the price. Now when it comes to images in Shopify Hydrogen, Shopify have this amazing component just called image. If I just do import the image component from Shopify Hydrogen, and then if I add the image field over here, actually, let's do this query back in a graphical interface over here. Then if I find what the field is that I'm looking for, this is the handy part of using graphical. I've got auto-complete here. If I forget what the name of the image field is on this particular node, it's going to auto-complete it for me. Then if I try and run that, you'll see that it errors because I have to have selections here. This is going to return an image connection, I believe. If I hover over it, it's going to return an image. What we can do is look up the documentation to see what fields are on the image object. I'm here at the storefront API reference. Let's go into online store, go into objects. Now I believe it's in common objects. Here's the last place you look. Here you can see the image object, and then here you can see, to get the URL of the image, we can access it like that. We can get the altText, we can get the width. What we could do is go in here, grab the URL, and then we could just create our own basic HTML image and bring in that SRC. But then we wouldn't get the benefit of responsive images. What we can actually do instead is use the image component, if I go over here, from the Shopify Hydrogen framework. I'll show you how that works in just a second. But first, we need to flash out this query right here. I'm going to grab the altText as well. I'm going to grab the height and I'm going to grab the width. Let's just run this, make sure there's no errors. We've got the title handle and data relating to the featured image. I'm going to grab that and paste that back over here inside our query. There we go. The nesting is a little bit off. Tap it in like that. Then so what I'm going to do here is open up an image component right here. How this works is we can put in inside Alt, we can access the featured image objects on the product and then grab the altText. But then for the rest of the image data, we can just parse in through this data prop, the image object itself. I just need to close that. Then if I hit "Save" on that and we refresh over here in our hydrogen app, you can see all of our images come through. If I right-click and inspect them, you can see that we've got lazy loading built-in, and we've got all these different responsive sizes based on the screen width. In Shopify Liquid, you can do this optimization by creating a snippet and using the image URL filter to create different image URLs to serve based on the dimensions of the image within your Shopify store. But here, all we have to do is use the image component within Shopify. To show you the alternative, for instance, if we just did an image tag with SRC and then we could just simply parse in product.featuredImage.url, save that, refresh over here, you get the same result, but you see how it's loading a bit slower. Then if we go in here, we see we've only got the one SRC. For responsive images, we don't have to go through and write all the code ourselves, we just need to use this handy image component provided by Shopify Hydrogen. As you can see, it's already reloaded and you can see now we've got lazy loading enabled and all these different URLs automatically generated for us. That is the power of using some of these components that come through hydrogen. Some of them unnecessary and some of them just make our lives so much easier. We'll see that when we do product options and we do cut as well. Maybe we could do that without these components, but they just make our lives so much easier and I hope you guys are starting to see that now. What I'm going to do is wrap this in an image container. This is just some CSS to get it showing up exactly how we want it. We're running out of space here, so I'll open this up. Then underneath the image container, I'm going to put in a div here with the class of product-grid-item-title. Then here I can put in the product.title, and then let's hit "Save" on that, refresh over here and you can see we've got the title of the product and the image. But usually on a product grid you want to see the price as well so let's do that next. We're going to need to bring in some extra data for that because currently we only have the title handle and featured image. Let's go over to graphical again. Then underneath featured image, if we type in something like price, which is going to get the price range and the compareAtPriceRange. Something that's a bit more accurate is to actually dive into the product and grab its variant. You'll see we can access price range and compareAtPriceRange. But if we want to get a specific price, what we can do is dig into the variants. What I'm going to do is I'm just going to look up the very first variant. Of course, this is a selection with nodes within it, so we're going to have to open up nodes. Then within variance, I'm going to grab, let's see what comes up for price. We've got priceV2, and that is actually a selection itself, so we have to go in and grab the amount and the currency code. Then if we want to have the compareAtPrice as well, we will need to do the exact same for that as well currency code. If I hit "Save" on that it will not save but run on that. We look down here. You can see that for this hydrogen snowboard, the price is $600, but it actually has a compareAtPrice of almost $650. Obviously this works, I'm going to copy that. Paste it back into our project. Unfortunately, I think we're going to lose our nesting. No actually doing okay with the nesting. Hit "Save" on that and then over here what I can do is create a new div here. I'm going to use the class of product-grid-prices and in here, I can do product.priceV2.amount to make it real simple to start with. What have I done wrong here? This is not matching up to what I've got here products. I forgot to go into the variant. We're going to go into the variance and go into nodes, grab the first node. That's a spelling mistake, variants.nodes , price to amount. There you can see we've got the price coming through, but it's not formatted. What are we going to do? Well in Shopify liquid there's a filter for this, which formats the price nicely for us. We've got a similar thing within Shopify hydrogen called the money component. I'm going to import the money component right here and then let's take away that and then open up a money component here. Then just like we did with the image, I can put in the data prep that same price, but I don't want to go specifically into the amount. This component is going to figure out what the amount is and what the currency is and format it nicely based on those two. I've made a mistake here. I've got two curly brackets, and that has stopped my server. Let's run the server again, run npm run dev, and then rerunning our catalog page here. You can now see we've got the currency symbol, and these prices are formatted as currency. We've got nicely formatted currency here. Now for completeness sake, let's actually build in the compare at price as well. What I can do down here, let's just do this to get started, and then we'll clean this up. I will go into here and I will grab the what was it compare. Let's go back to here. Compare at price V2, put that in here, and close it just like that one. Now we're going to get the two prices side by side. Maybe not. We have got an error here, which is interesting, that does seem to match up to what we're returning here. Let's just use a console log to debug here. I'm going to console log products object here. We can see what's being returned. You've got title, handle featured image. Let's go into variants, nodes, and rerun. Scrolling up here if we go. I see. Sometimes compare out price V2 is null and that's why there's an error. Sometimes there is a compare at price V2, but sometimes it's null. What the money component is trying to do is access and attribute on an object that's now. We need to make sure that we're checking whether this is actually null. We can do here is if it is returning a truthy value, then we can put in this basically return statement here and then run that compare price. Here you can see on these ones where there isn't a compare at price is just showing one price. Where there is a compare at price it's showing both prices. Now, this is messy obviously. Look at this, this is not very nice. What we're going to do is clean this up here and then put in something a bit nicer down here. I'll get rid of this console log. What I'll do is I'll use object de-structuring to take off these attributes off of this node right here. What I'm going to do is grab the price V2, and I'm going to pull it off as just price. Then I'm going to grab the compare at price and I'm just going to pull that off as compare at price, not the compare at price V2. We don't really need that V2. I think that's just API versioning right there. Then we're going to grab that off what we have down here, product.variants.nodes, and then grabbing the first one in that array. But we need some fallback in case any of these are null. We're going to put a question mark here. If it is null or undefined, we'll just pass through an empty object. Then instead of checking whether this is now what we'll do, which is a bit more sophisticated a bit nicer, we'll just check if the compare at price amount is greater than the price of it. I'll call it is discounted. Then we'll put in a Boolean here, compare at price question mark in case it returns null, amount is greater than price question mark in case it returns null amount. Then, so here, I'm going to change these right here too, is discounted. If it is discounted, it's going to return this. Instead of having the price represented really long here, we can just use the price that we pulled off up here, price, and then compare at price. If I hit "Save" on that and let's refresh over here, you'll see we get the same result, but it's a bit cleaner and in our JSX, it's a lot nicer to read. I'm also going to give this one a class name of products compare at price. Then if I hit "Save" and reload, now you can see that compare at price is clearly the markdown price visually because we've got some CSS that applies on it now. One other thing I'll show you before we wrap up is, as you can see, some of these have.00, which you may not want showing on the front end. Obviously, if there's a value in these decimal places, you probably don't want to round up. But when there's something like 600, we don't really need to go to two decimal places. What we can use is similar in Shopify liquid with price formatting, we can put in something like without trailing zeros. Then if I hit "Save" on that and go back, you can see all the products that had.00 are going to have that removed. That's another cool little formatting option there. I'm going to leave it there for the catalog page. What we'll do in future is we'll make these linkable. But because we don't have a product route created yet, is just going to result in heading to a 404 page. We'll keep it like this for now. In the next video, we're going to learn how to send through a collection handle in the URL and query our storefront API to return only the products within that collection. Essentially, we're going to be creating a collection page in the next video. 9. Building a Collection page: So in the last video, we created a catalog route, which is showing all the products in our store. It's not filtering by a particular collection. Actually correction, it's only showing the first nine because we have only queried the first nine. But if we extend this to 100 or whatever, we'll get the first 100 or up to however many that are in our store to begin with. If we put in 100 here and I hit "Save" and rerun this, we won't get 100 because there's not 100 in total, but we'll get up to 100. So I believe there's 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12 snowboards within this hydrogen preview. I'm going to put that back to nine. Notice make our site run faster, but we can always update that to however many we need. In this video, what we're going to do is create something very similar to this, so we'll create another product grid, but with this particular route, it'll be a dynamic route. So we'll be able to go to collections/ something like shoes, as I've got pre-filled here, and then we can go and look at a product grid that's filtering only to that collection. What we'll do for this is we'll head back into our code editor here and we'll go into routes here, and because it's going to be a Nested Route, so it's going to be collections and then it's going to have the name of the collection or the handle of the collection. We need to create a folder inside our routes folder here, call it collections, and then in here we're going to do something which is a little interesting. We're going to put in a dynamic route, we're going to put in the handle as a variable and then type server.jsx. Now what I'm going to do here is I'm going to pull all this information, basically copy and paste everything from this right here into this right here, and then of course, I'm going to need to update this from catalog to collection, and that's all I'll do for now. Let's see, we've got an issue here. We need to update the puffs up here that lead to our components because we are now nested in, as you can see here, another folder within our route so we're going to need to add dot, dot dash, another set of those two, both of these so that we can navigate to the right place or run npm, run dev again. Then if we refresh over here, we should be all good. That was one thing we needed to update as well before it can run. Really the only difference here in this route compared to our catalog route is that we're going to pass through the handle and so obviously we're going to need to use that information. We're going to need to pass that through to our query down here and then the query is going to return only the products that are from that collection. But essentially here in our JSX, there is virtually nothing to update. What we're going to do in order to use the route parameters, is input a new hook from Shopify hydrogen, might put it here. useRouteParams, is the name of the component and then we can use this hook to pull off the handle from the route params, so I'm going to use the structuring here, grab the handle, which will come from useRouteParams. Now in order to pass that variable, that handle through to our query using the useShopQuery hook, I'm going to have to add in my variables here. I'm going to open up an object and then I'm just going to pass through the handle. Now if I scroll down, I can use that handle inside our query. How do we do that? First of all, I'm going to rename this query to something more appropriate. I'm going to call it CollectionDetails and then in our title, we want to specify that we are going to pass through a string as the handle. Then instead of looking for products, I'm going to use Command X to cut to that, so removing it from our query to start with, but then I'm going to paste it back in later. Now what we have to do is actually query finding a collection, and the way we're going to do that is by its handle, just like this. Then inside here, we're going to grab some details about this collection, ld, title, description. Let's grab some SEO information as well. That's a selection, so within that selection, we need to grab the description and the title. We could grab the image of the collection. We're not going to use it in this particular class, that's just an example. But we can pull whatever information that we need off that collection object, and then I'm going to paste in that code that we had before. We can then on that particular collection. Find the first nine products and then use that same information. Let's just try and fix the indenting here a little bit, that was futile. If I hit "Save" on that, let's now run. Actually we need to know what is a collection in our store so in order to do that, I'm just going to go in here and query our store right here for the first nine collections, and then I'm going to type in nodes to access each node, and then I'm going to look for the handle. This is just in order to see what handles are available on the store at this present time. So here's all the different collections via their handles. The first nine at least, but there's only 1, 2, 3, 4, 5, 6. This is all the collections within this particular store. I can now go over here, go to collections, and then put in that dynamic route passing in the handle of the collection, I'll hit enter on that. We've got an error, so what have we got? String isn't a defined input type, so let's go back to our query over here and I have mistyped this. I need to put this as string with an exclamation mark. This is just a syntax error on my part and then if I refresh over here, what have we got now? Undefined reading nodes. This is related to the setup I've got up here, because now our nodes are nested within products, within collections, not just products. Let's just comment this out for a second and I'll console log the data that's being returned from the API, so if I scroll up here, you'll see we've got collection first. So we're going to need to update that. Let's cut this like we did before with the query, put in collection and then paste after that. We need to put in another curly braces and then products nodes. Now you can see it works. This obviously looks quite similar to the catalog page, so if we want to confirm that this is actually that collection, what I can do is let's put in a h1 here and we can grab data collection dot. What did we access? Title? I've accidentally opened up two curly brackets again here. We just need one on either side, and then if I hit "Save" on that, refresh over here, got another error here. I haven't set this up properly, so data collection, I think we need to go data twice here, data.data.collection.title, and here you can see Freestyle Collection. Then if I go into what was one of the other ones? Back country, so if I go into backcountry, now we can definitely see that the list of products showing up different, this time, definitely compared to the freestyle collection. Now you can see we can pass in the collection handle and return only that collection. Now this is ugly, so let's clean that up a little bit. Let's do data collection, collection from data, and then should be able to just pull the collection title off like that, and we can probably make that even nicer by putting that up here. Then this structuring from the collection, whoops. Now we just need to whoops, collection. Let's see if that works. So that's a little bit nicer as well. I went through that a little bit fast, but basically I'm just structuring enough from the data object to get the collection and then see me, I've got that collection object now. I'm then pulling off the product nodes from that now. That results in less nested destructuring and allows us to grab stuff like collection.title, and nodes off of these objects right here. So because we've already created our product grid item and recycled that, there's not a lot of work here to do. What we've done in this video compared to the last one is pass through that handle so obviously this one didn't have any handle coming through and we just accessed products on our query root. Now we're accessing the products on our collection, and of course we need to specify which collection we're after. We do that via the handle and we figure out the handle via the route params, and it just means that we've got one level of nesting deeper because we're looking inside a collection, so that forced us to update our object destructuring up here. But otherwise we have now got collection pages set up on our store. So in the next video, what we're going to do is create our product page now, so we can actually, when we click on these items, go into each of these products. 10. Building a Product page: In the last two videos, we set up our product grid inside this catalog page, which returns all of the products within our store. Then our individual collection route, which is a dynamic route which we can pass through the handle of any collection we want to load. I apologize for the slow connection speed here. But here you go. Here's our freestyle collection. But as you can see when we click on any of these, they are not linking to any individual product page, because we haven't built that yet. That's what we'll do in this video. In the video after, we'll create the cart functionality. In the next two videos, we might see the complexity increase a little bit because the two biggest parts of interactivity, you might say, within a Shopify website are often variant selection and the cart functionality. These are the areas of our Shopify site that we usually want to update instantly managing state on the front end. Luckily for us we're using React and we're using Shopify Hydrogen. All of that asynchronous functionality is going to come naturally to this platform. It's one of the benefits of using React and Hydrogen. But it's going to mean that we're going to use a few more providers and a few more hooks in order to get that functionality going. But as you'll see, after we run through this, you'll start to see that there are so many components and hooks in Hydrogen that are enabling us to do this. It'll be quite simple once you get your head around it. Before we actually build this product page, I'm going to update our links up here because we do have a catalog page and a collection page now. I'm going to go over to our layout component, and then in the first link, I'm going to link that to our Catalog. The second link, I'm going to link that to collections Freestyle. Might as well just do this one, Freestyle. If I hit "Save" on that and it will refresh over here, you'll now see that we can navigate to our Catalog through our header navigation, and we can navigate directly to that Freestyle Collection through our header navigation as well. Let's create this products route. Just like we did for collections, we're going to create a dynamic route, but we've got to nest it inside our products folder. Then in here, I'm going to do the same title as before, handle.server.jsx. Then as I usually do, let's export a component right away. I'm just going to call this Product and then a return statement in here for our jsx. It doesn't like me doing that. You always got to put some jsx in-between here, otherwise it freaks out Let's just put in some jsx here. That way it won't stop our server from running npm run dev. Because before we start to build out this component, what I want to do is start testing out some GraphQL queries right here. Instead of query products, let's do a query product. Then in order to target a specific product, we're going to do the same thing as we did before with collections. I'm going to specify that we are going to pass in a handle and the type is going to be a string. Let's knock out this stuff here. Then what I'm going to do is grab a product via its handle. The handle is going to be passed through in the variables of our useShopQuery hook, just like we did for collection. Now once we determine the product, I am going to return the title of the product. What else do we need? Description, HTML, and then we'll want to return the image of the product. We can go through the media. Media can be 3D models, it can be images, it can be videos. But to keep it really simple for this class, we're just going to handle images. I'm going to open up media here. Also to keep it simple, we're just going to display one product image. I'm only going to select the first bit of media. In this particular Shopify store, we can attest that the first media is going to be a product image. Otherwise, maybe we would want to look for multiple media and then make sure that we are finding an image out of this list of media. But I think it's pretty safe to assume that the first bit of media is going to be an image. Continuing with that assumption, I'm going to open up nodes here. Then for the media fields, again, this is assuming that it's an image. If you wanted to make this work with all types of media, you would need to do what I showed you in one of the theory lessons, which was having those three dots and saying on MediaImage. Actually let's still do that. If it is a MediaImage, it's going to return this selection, ID, and then the image itself with the URL, width and height. Again, we're only going to be dealing with media images in this particular class. But if we wanted to have a different selection based on if it's video, we can just go on Video and then put our selection for videos. You do on sources. This is just like the example that we saw earlier on the Shopify documentation. But for this class to keep it simple, I'm just going to assume that we're only looking at images, which I believe in this particular hydrogen storefront. I don't know if there's any 3D models or videos anyway. It's a pretty safe assumption to make here. Then let's just run that to start with. Actually, we need to pass through a variable here, so it's probably not going to work. We don't have a variable. Maybe I want to play around with it here because we don't actually have a handle the work with, but let's actually grab this, and let's put this into a query here. If it breaks, it'll break within our application and we'll just test it here. We'll do gql to house our query. Then we'll put it there. Then of course we need to import, useShopQuery that all important hook from Hydrogen. We also need gql. Then if we're going to use CacheLong, grab CacheLong as well. Then in here, let's just do a const data. We won't destructure it just yet. Then we'll useShopQuery. We will do the query as the constant query that we've listed down here. Cache will be CacheLong, just like before. Then we'll pass in the variables of handle. How we're going to pass in the handle, we're going to have to use route params again. I'll grab useRouteParams. I'm running through this pretty quickly because this is the same pattern we did for the collection as well. We're just going to pull off the const handle from the useRouteParams hook. Then if we don't specify handle here, we can write the short form of just handle. Obviously we got a bit of an error here which has caused our server to stop. But let's just console log this data and see if we've got an issue with our code at the moment. That looks okay. Now we're still going to need to pass through a handle, so let's build that into our ProductsGridItem. I'm going to input another component up here from hydrogen, the link component, and I'm going to transform this from a div into a Shopify link component. Then in here, I'm going to do to, grab the product, and go to its URL. Actually, before I do that, I'm going to need to put in the preceding products part of that path. Let's hit save on that. If we go back over to here, and let's go to that freestyle collection or any collection page or catalog page where ProductGridItem is in use. Now our images are currently linked. If we inspect any of these, you can see that it's heading to undefined. That's not going to work [LAUGHTER] undefined. We got to figure out what the issue is there. Product URL. Perhaps we didn't request that. Let's go to catalog. We're not going to use the URL, we're going to use the handle. That's how we're going to construct the URL. Refresh over here and then have a look here. You can see snowboard is the handle on that one. The handle for this one is mail-it-in-freestyle-snowboard. Interesting names here. If we go here, we can go to that particular route. Currently, there's nothing coming up on the front end. Let's go back to our code over here, and of course, we console log to the data. Here you can see, and I'm going to expand this out so you can see easier, we see what is returned from the Storefront API. It looks like our query has worked, we have passed in the handle, and we have gotten back the title and the description HTML, and an object containing the media. We'll have to go deeper into that object if we want to see what's inside. Now I'm just going to add also the variant information to this query because we're going to definitely need to use that in order to do the variant selection once we get to it. I'm going to attempt to grab all variants. I think the total number of variants you can do in a Shopify store is 100 anyway. I'm going to try and grab all the variance using the argument of first 100. Then that's obviously going to return a list of nodes. Inside of nodes, I'm going to grab the variant ID and a bunch of other properties that are going to help us. We're going to need to grab the priceV2. Then of course that is a selection, so we're going to need to grab the amount and the currencyCode. Let's also grab the CompareAtPriceV2. Same thing again, amount, currencyCode. If we wanted to, we can grab the variant image, but we're just going to use the one image that exists on the product for this particular class. But one thing we need to bring in which is going to be essential for figuring out which variant is being selected is selectedOptions, so we can grab the name and value. I think that's all for now. If we reload over here, as you can see, it just says object. Let's have a look inside of data variance. All we do, we need to nest. Now we need to go into data product.variants. Let's refresh the page over here. We've got an error undefined on variants here. Let's have a look. Data, product, variance. Product is coming back undefined, which is interesting. Go back to console log-in data. I'm leaving this in the class for you guys to see how to debug. If you don't know what's coming through in the data, you can always just console log it and then you can figure out how to do your destructuring and accessing different parts of the data that gets returned. As you can see here, we've got a data object. I think I need to type in data again. Data, data, product.variants. Here you can see that's what I needed to do. Here we go. If we go down here, we can see the list of variant nodes and you can see the Storefront ID of that variant, the price as an object, and the selected options as an array. If we wanted to go even deeper into that, go to the first variant, so we're going into nodes, the first node that comes through on that variant array, and then go into selectedOptions just to have a look inside. As you can see here, for this particular variant, the size of 154 cm, and the color of syntax. This is what we're going to need to know in order to determine the variant. Basically what we need to do here guys is pull off the product off of this data right here. I can either destructure down here like I did before and do this off of the data. Or I can save some space and move this up here, which makes it look a little bit more complicated, but it's a bit cleaner. That's how you'll see it in the Shopify examples as well. We should now have access to that product if we're passing through a correct handle. Then what I can do here is product.title. Then if we refresh over here, still not coming through. What are we doing wrong here? Nothing is coming through in this div, which is interesting. Let's have a look at our product objects. If I refresh, you can see product title here. I believe that it might actually be nested. Product.product.title. Yes, and that works. That's a bit funky, isn't it? Let's do data. Oops. We'll clean this up a little bit. Data, data product. Then now we should be able to remove one of those products. Nope, doesn't like that either. I'll do products, and there we have it. We needed to update our destructuring here in order to get that product object. But now we have that product object, we can start to use it right here. Now one thing you'll notice is we've lost our layout, so let's update that. We want to put in our layout component here and nest this inside. Let's also give this product page some SEO information. I'm going to grab the SEO component. Inside of layout because we are querying the database or querying the Storefront API in order to get the SEO information, I'm going to wrap it in a suspense. We need to import suspense from React. Then inside here, the SEO component. For this, we just need to type in type product and then just pass in the product as the data object. The SEO component will do the rest of the work for us. Then down here, I'm going to give this a class name of product-page and container which lines up with our predetermined CSS. Another area here, layout is not defined. Cool. Actually, let's put it down here because it's our own component. Import layout and it's already pre-filled the rest of it for us. Beautiful. There you go. We've got our header layout back now, and so if I go to any of the products in any of the collections and click on them, you'll see it'll go to that handle, and then it'll load that product information. Right now we're only using the title. Let's actually build out this product page a little bit more. To do that, in order to decouple this querying of the Storefront API inside the server component, I'm going to create a client component for holding our product page. This is probably going to be a bit of a longer video because there's a lot of code to get through here. But let's just clean this up a little bit here. Definitely going to want to have a look at this, but then we're also going to want to create our productDetails component here, Client.jsx. Then again, like I do when I start every component, export default function, name of the component, we'll call it product details. We're of course going to pass in the product data as one of its prompts. Then of course we're going to return some form of jsx. Make sure not to save without anything in here otherwise, it's going to error. On that note, let's just create a div to avoid that situation. Just like we did before, I'll put the product title there. Then instead of this, what I'll do is I'll import productDetails from that address. Then I will replace this with productDetails and then passing in the product as a prop. There we go. If I hit save on that, refresh over here. Another error. We've got this no localization context available error here which is a tricky one to debug. What I found was I just had to use Yarn to clear the cache. This is what I was mentioning earlier about Yarn. I was initially using npm run dev every time, but then I installed Yarn because it ended up being the only way to get around this issue and so instead we're going to close down the server which I just did and then I'm going to run yarn dev --force. That's going to re-run our server, and as you can see now it's working. That's just a weird quirk within Shopify Hydrogen development. If you ever have a weird error like that again and you can't figure out what's going on give this command ago, yarn dev --force. Obviously in this case it has worked and we can move on. What I was trying to show you before that error came up is that we've now moved that dev with the product title into its own component and then replaced that with the reference to the components. Now if we have a look at it in our browser, it looks exactly the same. But the reason why we want to move this over into its own component is related to server-side and client-side rendering. As it says in the documentation if I look over here to the React Server Cmponents overview in the documentation and I scroll down, you can see here that we should use server components when making calls to the storefront API and we should generally use client components when we're doing client-side stateful interactivity. That's why we are now going to break off the product details. We should anyway, just to make it cleaner code, but this perhaps explains more why we're using a client-side component up here. We're seeing our first client side component in the class so far. Let's go over here. In order to expand out this Product page I'm going to import a lot of stuff from Shopify Hydrogen, so let's get started right away. I'm going to import some providers and hooks here that is going to allow us to do variant selection much more easily. I'm just going to put in the path to hydrogen here first, and then I'm going to break up the curly brackets like this because there's going to be a bit of a list here that we're going to import. First of all you want the ProductOptionsProvider, then within that we're going to use the useProductOptions hook and then we're going to render an image obviously; ProductPrice which is very similar to the money component but is related specifically to ProductPrice. Then the Add to Cart button which we might not use in this lesson, but probably in the next lesson when we start to incorporate the cart functionality. Now instead of what we have here, I'm going to wrap the entire product details in the ProductOptionsProvider. This provider is going to give us some key functionality regarding variants switching, and because this can affect everything including the product image theoretically I'm going to put that as the top-level component. In order to get this to work, we just need to pass in the product as the data prop. In here I'm going to create an image and we just need to pass in the data exactly where that image lives. Let's console.log up here so we can figure out how to navigate to where that image information lives. I'm going to console.log the product object that gets passed through and to ProductDetails. right here I'm going to remove that otherwise there's probably going to be an error. Now let's switch over to our client-side in order to read our console.log. Because this is a client-side component, we now see the console logs in our browser on the client-side rather than here in our terminal on the service-side, so that's something to note. If we're working with server-side components, any console logs will happen here. If we're on client-side components, any console logs will happen in our client side, in our browser. We've got an error here because we're not putting anything in image, but essentially we've still got the console log coming through. If we go into media nodes and then go into this image here, this object should be all that's required to get the image to work. Let's have a look. We're going product media nodes; the first node, and then image. Let's do that, data={products.media nodes[0]; we'll grab the first one of the nodes, and then.image}. I'll hit "Save" on that refresh over here and let's see what happens. The data prop should have the alt texts property. It's not liking that, let's have a look. Maybe we just need to pass in the alt as it says here, so let's go down to our image and do Alt Text here. Let's have a look inside our elements main image. It is rendering, but it's freaking giant. It looked like it wasn't showing up, but it is actually showing up. I just have to put in a class name here to get it to behave, so I'm going to do className. Again referencing the CSS I've already created for you it's going to be product-page-image, and then now you can see it's nicely on the side there. Again, this is assuming that we are only using images for our product media. This would essentially break down if somebody was using video or 3D models in their product media. Just keep that in mind, this is a simplified version for the purpose of this basic class on Shopify Hydrogen. Let's now inside of this ProductOptionsProvide component put in a second component, and this is where I'm going to put in my product form. Let's create it first. This is the first time we're going to see two components in the one file. We don't need to export it because we're using it directly in this file, so I'm going to call this one product form. Let's do a return with a div in here so that the whole application does not break just as a placeholder. Then what I want to do is actually I want to make sure I'm passing through a product as a prop, and then I can grab that ProductForm components which we've just defined down there. Let's make it self-closing like this, and then I can pass through that product as the product prop. Then just like before, I'll just put products.title here. Let's run that, see if it works. Now you have the products image and the title here. Now nested inside this ProductForm component is going to be the useProductOptions hook. Inside of here is where we're going to start to create our variant selection functionality. Right here; and this is probably the most complicated part of the video so bear with me guys, I'm going to pull off some things from this hook; useProductOptions, and this useProductOptions is the hook for managing the state of what options are selected and therefore which variant is selected from those options. What we can do is pull off the options, we can pull off the selectedVariant, we can pull off the selectedOptions, and we can pull off the setSelectedOption method. It's easier for you guys to read, let's nest it like this. We're grabbing all of this from the useProductOptions hook, and then in here what I'm going to do is start with a div but I'm going to put the title as a h1 and then underneath that I'm going to utilize that ProductPrice component, so I'm going to grab the ProductPrice, give it a class name of product-page-price. For CSS I'm going to pass through without trailing zeros as we did before. Let's break this down onto multiple lines for you guys. Without trailing zeros, I'm going to pass in the product object as the data prop and then I'm also going to pass in the variant ID. This is important because the ProductPrice could change based on the selected variant ID and we can actually grab the selected variant ID like this. This is really cool. We're grabbing this which is a variable on this state object, so this is actually going to update as it updates based on our selection. That is the power of using this hook, and that is the state that we were talking about in this particular component that we're going to use. You'll start to see this working in just a second. If I refresh over here, you can see we've got a price coming up here. It doesn't actually have trailing zeros, so that without trailing zeros isn't working on this particular page but for any page that has two zeros; two trailing zeros, it will remove those but as you can see here the price does come through. Again, my shoddy Internet connection is making this load slowly. Internet situation sorted for the time being, sorry about that. There you go. We've got our price coming through right there. A good idea would be obviously to create another ProductPrice here and do what we did on ProductGriditem in terms of if it is discounted show the Compare at price as well. But I've already shown you how to do that, so you should be able to figure that out yourself. In the interest of time and making sure this lesson does not get too long, let's get on with the most important part which is the ProductForm itself. What you're going to see here is that I'm going to nest another return statement, so this is going to be based on an array and this section we're going to house in a div with the class of ProductOptions. Then in here we're going to access all the options in order to create our product form. We're going to use map again, we're going to take each of the options. We're going to use the structuring to grab the name and values off of each option. Then we're going to create a full back here, just going to have to add a bracket there. So this doesn't break and remove that. There needs to just move this here to address that error. There we go. The red squiggly lines are gone. Then what we're going to do is put an if statement here just in case there's only one value, in which case there's no option for selection. If there is one, we're just going to return null. This is just a fallback in case there aren't any multiple values, in which case there's no point selecting from options if there's only one option. Then if that's not the case, we're then going to return another set of JSX. I'll try and do this step-by-step as possible. So we're going to first create a product option group for each group of product option group. I'm going to put in a key here because it's a requirement of react. We can use the name here as the key and then I'm going to put in a elegance elements here with the class of products option dash name, and then I can put in the name of the option. Let's leave it there for now and let's have a look. As you can see, what we're going to get back is the list of different options. If I go to my catalog here and go to, I believe it's this one with the most amount of options. You can see when now listing all the different options. But what we're not listing yet is the values. Let's go through that right now. In this next bit here, we're going to nest another return statement. This is where I'm saying it's starting to look a little funky here. There's a lot of nesting going on here. It's just the nature of the beast unfortunately. We're going to use another map here to pass our values into some JSX to display. I'm going to grab the value, open this up, and then I'll put some code before the return statement. But just to start us off, just to get something on the page, I will open up my returns straight away. Here is where I will put in a div with a class of products option value, and inside here is where I will put a radio button. We'll do type of radio. Name is going to be equal to the name of the option. Then of course we want to record the value. We are currently looping through all the values so we can pass in the value that we're currently looking at and then we're going to pass through and onChange method. This is when we start to use the sets lectured option method that we grabbed off the use product options hook. Now I'm going to put in an anonymous function set selected option, parsing, name and value and close off that input element. Now let's see if we get any errors. It's not completely complete, but I wanted to show you what we have so far. We have some space here, but there's nothing coming through. Let's have a look. We've got the legend and then we've got an input for each of them. Oh, I forgot to put the label here. The reason why these inputs I've nested within these divs is so we can put a label in, which is a nicer look for the input rather than having those ugly radio buttons. It's just an HTML thing here. I'm going to create this label and then I'm going to put the value here so we can actually see what value we're selecting. As you can see, the values are coming across now. As I hover over each option, there is a line that comes underneath. As I'm clicking these right now, the set selection option should be working. We're just not getting visual feedback on our form. In order to get that, what we're going to do is create a variable up here called checked and we're going to access the object that we haven't accessed yet. We're going to access this which we haven't used yet, selected options. If, when we pass in the name into selected Options, it equals the value that we're currently looking at, then checked will be true. Now we just need to pass it into our input here. Checked equals the value of that one. Hit "Save" on that. Now you can see actually it's still not working because we've got one more thing to do here, and that's created our id. We're going to do const ID. Let's create a little string here with both the name and the value. Then we can put that both here and then also in the label, put HTML for ID, and that'll link our label to our input. This should be all that's required to work. Now if I click on any one of these, okay. It's not working still. What have we got going on here? Each child in the list should have a unique key prop. Maybe that's the problem we have here. Right here, let's use that newly created id as our key prop here. Hit "Save" on that. Refresh over here. We're still not able to switch our options here. We've got an error here related to what do we got encountered two children with the same key. Let's have a look. I forgot to put in my curly brackets here. It's literally putting in dollar sign value. It's not a dynamic value. As you can see here, you can already see now that it is saving a different selection. Hopefully that wasn't too hard to follow along with. As you can see here as I switch variance, the image is not changing, but the price is so the use product options hook here, is actually managing our state for us, which is really cool. Anytime we're creating a new selection here, we're selecting a new variant and that is automatically updating our price and anything else that is related to variance on our page. The one thing we're missing here, just to finish it off before we move on to the cart page is the description here. What I'm going to do is create a div with the class of product description. Instead of inserting HTML in there, what I'm going to do is type in this very weird-looking prop here called dangerously set in a HTML and then in here to underscore, underscore HTML and then put in our description HTML for the product. Description HTML. Let's close this so we can have a look. Then as you can see, here is our description. Now, why have we put it in this prop and not just, let's just delete all of that and then throw it in here. Well, let's have a look at what happens when we do that. I'll hit "Save" and as you can see, it puts through the literal HTML. We need to actually insert that HTML through a prop for rendering. The reason why the prop is called dangerously set in HTML rather than just in a HTML, is it's a reminder from react to be very careful when inserting HTML into an element that is coming from a database or an external source. The reason why is something called HTML injection. Somebody could actually break your page by putting in incorrect HTML here. So it's a warning from react to let you know that this is a little bit dangerous. But in our situation when we're inserting product description HTML, as long as we, the users or the admins don't put in any broken HTML into our product description field, this should work. But if the client or the admin or whoever is adding descriptions to products puts in some broken HTML, then this is going to break. All this does have the potential to break. That's why it says dangerously set in HTML. That's something to note there. That is a bit of a risk. This one has been a big one. I hope you have followed along. If you get stuck at any point, obviously leave a comment. But now if we go to any product in a store, some of these are less complicated. This one only has one option. We can select just a size. But this one right here, the hydrogens snowboard, I believe is the most complex. It has size, binding mount, and material. We'll see in the next video when we add the "Add to Cart" button, that when we click that "Add to Cart" button, the variant is already determined from our selection, and so that variant will get added to the cart. So thanks for following along in this video. In the next video, we're going to do the biggest part of our app, which is the cart functionality. Basically the store doesn't function until we have a cart functionality so this will be the final part of making our store work. Maybe take a break, get yourself ready, and come back for the final lesson before we deploy our app to our Shopify store. 11. Cart Functionality pt. 1: All right guys, it's time for the final and most essential part of getting this store to work. This simple store, obviously there's a whole bunch of improvements you can make here, but in order to get a basic functioning store, there's one more thing that we need to do and that is to enable cart functionality. In this video we're going to stretch across a lot of different components here. We're going to update our app component, update our layout components to put in a cart button here, update our product page here to put in an add to cart button and create a cart page. Without further ado, let's get started. We might have to break this up into two videos depending on how long this gets. But the first thing, as I mentioned, I'm going to open up our app.server.js file here. In order to get cart functionality in our app, we need to grab the cart provider component and then we want to wrap our router in that. I'm going to cart that. It's still in the clipboard, put in our cart provider there, and then paste back in that router in-between the cart provider tags. I'll hit "Save" on that. Now, just like that, we're going to be able to use the hooks and functions of the cart within our app. Let's go into our file explorer here and let's create a new route for the cart page. Here now routes folder, cart.server.jsx. In the official Shopify tutorial, they use a drawer for this, but it's bringing in external libraries and pasting in a lot of code. I definitely recommend having a drawer as a design feature, user experience wise, but to keep it simple and focus on what we need to actually get this working, we're just going to do a separate page. Just like product details, we're going to open up a route here and then serve through a client-side components. This file will be pretty simple. We're just going to export default function cart, and then in here return, and then we're going to wrap everything in a layout component. I'm going to open up a div with a class of container, so everything is contained, and then I'm going to bring in a client-side component that I'm about to build code cart page. That's basically it. All we need now is our imports. We're going to import layout from components/layout server. We've got a layout there, and then we're going to have to create this components, so I'm going to create a component called CartPage.client.jsx. Then we can create a component in here, export defaults function carts page, return, a basic div to start with, and then we can import that. Import cart page and the rest is pre-filled for us from Visual Studio code. We wrote a bunch of code there, all basic stuff, all stuff we've done before, let's see if it actually worked. If I go to my cart path here, if we look inside our elements here, go into main, we can see there's a container with a div inside. We can guess that this is working and we're on this particular route. That's all we need to do for our cart route. All the work we're going to be doing for the cart page is going to be in this client side component. Just like the product details component, we're going to have to import a lot of different components and hooks from Shopify hydrogens. I'm going to do what we did before, break it up over multiple lines, and put the from ready to go. I'm just going to go through all the hooks and components that we're going to be bringing in, so we're going to need to use the use cart hook. We're going to use a provider component called cart line provider, we're going to bring in the image component for showing an image, we're going to bring in the use cart line hook, we're going to bring in the money component for formatting money, we're going to bring in the link component for linking to the product, we're going to bring in the cart costs component. As I said guys, there's a lot here. We're going to bring in the cart line quantity component, and finally we're going to bring in the cart line quantity adjust button component. I wasn't lying when I said there are a huge range of components within Shopify hydrogen, but they also have a purpose and they make our lives easier. Trust me on that, you'll be happy once we start to develop this page that all of this exists. Now, what I want to do is break up this cart page into multiple components. What I'm going to do is I'm going to create a suspense here. You can see it's automatically imported from react for us, and then inside here, I'm going to output the cart table, which we haven't created yet. Let's create that now. I don't need to export it because I'm just using it in the same file, and I'll just create this cart table component. The reason why I want to put this in a separate component is because we're going to be using some state variables in here. I'm going to be pulling off lines, checkouturl, and status off of this use cart hook. Then obviously they make this a component. We need to render some sort, so let's open up and let's just throw in a table HTML element. Now, currently we can reliably attest that there is no items in our cart, and that's because we don't even have a add to cart button on our product page yet. What is a good fallback to do straight away is if lines.length equals zero as in, meaning that there are currently no lines in our cart, there's no items in our cart, then we can return some JSX here and say something like no items are currently in the cart. Now there's a certain problem to this, and I want to show you what that is. What I'm going to do is put in a console log here, and let's just say no lines. If we run that, it's going to say no items are currently in the cart. Now, we'll get back to this in just a second. What we're going to do is, which one should we do first? Let's go into the layout component here and populate this. I'm going to put it in an icon here from an icon library that is recommended when using tailwind. In the official Shopify tutorial, they use something called tailwind and there's an associated tailwind icon library. We can actually still use the icon library even if we're not using tailwind. I forget what it's called, but if we just type in tailwind icon library, it should come up. Hero icons, that's what it's called. This hero icons is a library of SVG icons which SVG is now probably the best way of implementing icons in any modern day project. We can do it as solid, outline, or mini. I like the outline and I'm just going to type cart here. You can personalize this if you want. You can use this shopping cart. I like the shopping bag, and we can either copy the SVG or the JSX. We're using it in a react project, so we can copy the JSX, that's fine, and then I can paste it here. Actually, it's better that we use the JSX because right here you can see something I talked about in the theory lessons. This right here is linking to tailwinds, so I'm going to remove that. But here you can see if this was a standard SVG in HTML, this would be stroke, line, join, or actually I think that's one word, but there'll be a dash in there. Remember we talked about it in the theory lessons that we can have dashes. It's actually a good idea that we grabbed the JSX here, I'll just show you that right now, if we copy the SVG, there's going to be dashes in attribute names which we don't want. Definitely copy of the JSX if you're using JSX, which is what we're doing right now. I'm going to indent that a little bit, and as you can see here you can put a JavaScript expression in some of these attributes as well, and then of course I'm going to transform this into a link. Have we imported? Yes, we've imported link here and we're using it elsewhere. I can just go like this. Then I just need to link to the route, which is just going to be -cart. Right here we're going to put an indicator shortly on how many items are in the cart, but we'll get to that in just a second. If I head back to our application here you can see we have this cart icon here, and if I'm on any other page, if I click on this cart icon, you'll see it brings us back to the cart page. Let's go into a product page. Let's go into that first one that we saw once our app loads. Here we go, the hydrogen snowboard, and let's bring in and add to cart button. Open up our product details component right here. We're already importing our add to cart button up here. I'm going to go down to, let's do after the options but before the description, and let's create an add to cart button here. Actually we don't want it to be self-closing because we're going to add children here. We're going to put in here add to cart. Then in order to give it some styling, according to the existing CSS, I'm going to put in, add to cart as the class name. Let's go over to our application here and you'll see the add to cart button exists. I've just refreshed it, but there you can see we've got our add to cart button. Now, one thing we want to do before we click this add to cart button, or let the user click this add to cart button is to restrict it if it's out of stock. We don't want to show the add to cart button or we at least want to tell the user that it's out-of-stock if it is out-of-stock. Let's scroll up to the product form here and create a Boolean here. I'm going to create a const is out-of-stock and that's going to return true if the selected variant is not available for sale. If that doesn't come up, we're going to have a fallback here of false. Now, I believe that we haven't actually retrieved this from our GraphQL query, so we're going to have to do that. Let's go back to the handle.server.js x inside our products folder there. We just need to make sure that on the variant node, we're going to check if it's available for sale. We just need to update that, and then we've got this Boolean flag here is going to be true if the selected variant is not available for sale. What I'm going to do here is a ternary operator, going to break this up into a new line, and then put in a JavaScript expression here we have a ternary operator. If it is out-of-stock, we're going to say out of stock, and if it isn't out-of-stock, we're going to just say add to cart. Then also this should work, I'll put it in. If it is out of stock, it should also be disabled, so I'll put that in a disabled prop. That should work. I don't believe any of these products are out of stock, so we can't really test it, but this is definitely in stock. If I click "Add to Cart" now, you'll see there's a bit of a loading state there, but as it finishes, then that should be now in the cart, and if I click on this card here, now we'll get an error because we're actually dealing with some cart information. What does this render? Is not defined in cart table. Let's have a look at what we got going on here. I put render here instead of return. I'm such an idiot. You guys are probably screaming out from the other side of the computer telling me that I've got that wrong. Sorry about that. If we refresh over here, it will still say there's no items in the cart, but then it disappears. Interesting. If I refresh again, no items are currently in the cart and after awhile it disappears. This is the problem I was alluding to earlier. I said we're going to have to come in here and fix this. Basically, I don't know if this is a bug or something, but essentially the cart will return with no lines to start with, and then it will discover the lines later. When we first load it, it's going to say there's no items in the cart, but then it's going to disappear if there are items in the cart. What I've done here is I've brought off status from the returned object from use cart. Here let's have a look at what status is. If I console log status and then I refresh over here, you can see that three statuses come up fetching, uninitialized fetching, actually that's only two; isn't it? But there's three that comes up. Let me just put this on the other side so we're going to get the status no matter if the lines are zero or not, and then refresh over here. Here you can see we get fetching, uninitialized fetching, and then idle. Now, the reason why this is helpful is before idol shows up, it thinks that the line items are zero. But then when idle shows up, it realizes that's not true and shows the alternative, which is currently just an empty table. If we actually look in here and inspect, you'll see that an empty table is being rendered. But of course this table is the table that will house all of our items. What I'm going to do here is in addition to checking the length of the lines, I'm also going to check the status and I'm only going to show no items are currently in the cart if the status is idle. Otherwise, it could be in a loading state. If I refresh over here, if there are items in the cart now, it's not going to show no items in the cart. That's my little solution to that problem. We're already pretty deep into the video and we haven't even got a list of cart items showing up. Let's get into that right now. I'm going to give this table a class of cart table, again just for CSS formatting, and then I'm going to open up a t body tag here, and then here is where we're going to start to bring in our lines. We'll use that familiar map function again, and we'll grab each line, and with each line, we're going to return some JSX. Here is where we're going to put the cart line provider. We need to give it a key, so put through the line ID as the key, and then we'll pass in the line in the line property. Again, I can't really go into too much detail as to why this works, because it is just the nature of the component. These provider components provide functionality and they're set up by the libraries that we're using. You'll soon start to see what functionalities provides. We're going to use another hook inside of here, but what I'm going to do is create another component called cart line item. Then so let's go again, function CartLineItem. In here, what I'm going to do is return some JSX, obviously, I'm going to return a table row. What I'm going to use for that is going to be returned from another hook here. We've got another hook here of the structure some things off of this hook, but the hook that we're going to use here is useCartLine, and what we're going to do is grab the line ID, something called a merchandise, and the cost off of this object. In here, that's where we can use line ID, and then each of these rows is going to have, I think, four columns. I set it up. In here, in the first one, that's where we're going to put our image. Let's just say image to start with as a place holder, the next one we're going to have our product title. I'll just put in fake values to start with, so we know what's going to go in here, variant selection and individual price, and then the next one is going to have our quantity selector. Then the final one is going to have our line total and a remove button. If I refresh over here, you can see that we've got one row that is showing all of these placeholder values. That's not particularly handy, so let's try and make these dynamic. I'm going to remove these placeholders, and in here, I'm going to use the image component which I think I already imported. Yes, I did. Very good work, Chris. Let's go in here and give it a class name of LineItemImage for styling, and then all I have to do is pass in the image, which is actually in the merchandise objects. I can do a console log here for you guys to prove it. If you want to see what's in the merchandise object, you can just console log it yourself, but just trust me, when I say for the time being, to save time, the image is inside this merchandise field. If we pass through that and I hit "Save", now you can see that place holder has been replaced with the product image of our only product that's in the cart. Now we want to insert product tittle variant selection and individual price. Let's do that right now. I'm going to put in a link so that when we click this, it will go to the product. In here, I'm going to do products/ and then put in the merchandise products handle. On the merchandise objects we've got access to the product, and on that object we've got access to that products handle. Then I'm going to give that a class name for styling of line-item-product-title. Then in-between these link tags, I'm going to grab merchandise, products, tittle. We're using merchandise a lot here so we could do some restructuring here to make our lives easier. Maybe let's do that now. Let's grab off of merchandise. We can grab, I like to put in the best space, the image and the product here, so we can just remove merchandise from these is the benefit of restructuring, which we've seen multiple times throughout this class. I've put that link in, let's just check if that's working still. We've got the hydrogen snowboard there, and if I click on it, it'll take me to that product bit slow, but there you can see it's coming through. Then we want to, underneath this, put the variant selection. We're going to have to loop through the selected options, which is going to be on merchandise. I'm going to pull that off using the structuring and then I'm going to go selected options. May be there are no selected options, so I'm going to do a fallback of an empty array, and then I'm going to run map. Then for each option renders some JSX. Sorry, this is a mess when it comes to all these different brackets. Maybe it's just because I haven't put through my JSX expression here, which is going to be, again, we're going to use a key because we're looping through things, and I'm going to use the option name as the key, and then I'm just going to put in quite basically the option name and the option value on this particular variant selection. Let's hit "Save" on that and see how that works. There you go. That is the variant selection. The formatting is a little bit off. I haven't actually put this in a div with the class name of line item variant in order to get the formatting that I've already set up. There we go. Then for the rest of this, I might do that in a separate video for you guys because this one is getting quite long and Skillshare likes me to keep my videos under about 30 min to 20 min each. We're going to do a part two in this one, I will see you in the next video. 12. Cart Functionality pt. 2: All right. Welcome back. I hope you are ready to get on with this cart functionality and so obviously the biggest feature that we'll build in our little app. So it deserved two videos in order to cover everything. So we've got these placeholders still here on this side of our cart table. Just to recap what we did in the last video, we enabled cart functionality on the entire app by wrapping our router in the cart provider and then we created a cart route which links to a cart page and then we also added in a link to the cart right here and of course we added an add to Cart button, which is allowing us to actually add items to our cart. Let's get back to building our cart page. In here we're going to use some other components which we brought in or which we imported up here, cart line quantity and cart line quantity adjust button. That is probably one of the bigger names of the components that we're bringing in but these buttons are quite helpful as you'll soon see. Now for this one, it's important that you use the classes otherwise it's going to look like absolute crap. So I'm going to wrap all of this in cart quantity selector and then just to start us off, let's actually just bring in the cart line quantity and if I just put this in, as long as this is within a cart line provider, check this out, you'll see that the quantity is the correct quantity. So if I was to go to this snowboard and add another one of these to the cart. I think it needs to be the exact same variant and it's taking a while. Now we go back to the cart and now you can see it's up to two, so how good is that? We're already bringing in the state of what the quantity is on that line item just by using this component from Shopify Hydrogen. But of course we want to be able to update the quantity. So on either side we're going to put in a cart line quantity adjust button and then on the left side for the adjust parameter, we're going to make it decrease. I'm going to open that one up and inside I'm going to put in an SVG that is a minus symbol. So I'm going to go back to hero icons here, find minus copy the JSX, throw it in here. So we've got our decrease and then on the other side of the cart line quantity. I'm going to put in another cart line quantity adjust button and as the adjust prop is going to be increase and then the SVG and then I'm going to put in here is of course going to be the opposite, which is plus. So I'm going to copy the JSX for that icon, paste it in here, and then hit "Save" on that. Now let's see what happens when we refresh our page over here. You can see that I can now reduce it down to one, or I can increase it up to three or how many that I want to make it. So those are very handy components there from Shopify Hydrogen. We get some quantity adjustment functionality right out of the box. For here, for the line total, I'm going to replace that placeholder with a money component. I'm going to put in that without trailing zeros flag and then I'm going to pass through the cost dot total amount to format the total amount in a nice user-friendly formatting. So up here is where we're getting the cost from the use cart line hook. You should understand by now that if we just put that through, it wouldn't be formatted nicely. So we want to put that in a money component, which we can see here. If we're getting three of them, the total ends up being 1,800 and then the remove button is another cart line quantity adjust button. I'm going to put in as this as prop, I'm going to make it show up as a div, going to give it the class name of cart remove and then the adjusts prop of remove. This is going to tell the cart line quantity adjust button component that I want it to remove all of the quantity of this item. So just remove the line item completely and for that, I'm going to use a trash can icon. So I'll go into here, type in trash, copy the JSX, head back here just like we did before, and fix up the nesting. So if we have written all of our class names correctly and we go back here, you'll see that it'll show up in the top-right corner here and so we can just click that and remove the line item completely. Now you'll see that when we refresh the page, it doesn't show that there are no line items currently in the cart until we get to the idle state. That's to prevent this from showing up before we actually know for sure whether there's any items in our cart. Okay, so let's go back and add that item in our cart. Let's do a different selection here. Poly carbonate, classic bolt pattern 160, add to cart. Then go back to our cart over here and I think I wanted to put the price of each underneath here, so let's add that in as well. We already have access to our money component here. I'm going to type in money without trailing zeros because that's my preference and then inside the data, prop, put in merchandise price, v2, hit "Save" on that refresh and you can see the individual price is 610 and if I increase it up here, the price per each will stay the same, but the total cost of that line item will go up. Let me show you what happens if I add another product to the cart let's add a full stack snowboards to the cart and then I'll click on this to bring me to the cart page. You'll see we've got two here. Now, we've got a bit of a problem. One of these is showing up bold and one of these isn't showing up bold, which has an issue, but also we haven't got a footer here for the total, and obviously we need a button for checkout. So let's expand upon this. I want to go outside of this cart line item, back it up a little bit here, and then underneath here, put in a div with the cart footer and obviously we're going to get all these red lines because we need a single root element in our return. So I'm just going to do that hack that we use before of opening up an empty element and then just indenting here and then in our cart footer, I'm going to put in a link. The link is going to go to the checkout URL, which we pulled off of use cart. It's going to automatically generate us the Checkout URL. I'm going to give it a class name of Checkout button, which is set up in our CSS. Cool, so I'm going to close that and then in here I'm going to just have the word checkout and then close that link tag. If I refresh over here, you've got the Checkout button, but I still haven't put in the cart totals. I think I'm going to put that in the body. So right after here, where we're returning all of these rows, we can put in a final row and the first two columns, I'll do a call span of two. We're just going to have nothing and then we will have the word total and then for the final cell, we will bring in cart cost. Which gives us a total cart cost without trailing zeros and we don't need to pass through any information here as long as it's inside the provider, which I guess is the cart provider, this will be fine. So refresh over here and you'll see that those two added together equals that and I believe the bolding was due to my CSS making the final line bold. So the final line should have been the total. So now that styling issue is taken care of. All right. So we've got two of this particular variant. In one of this particular variant, if I click the "Checkout button", let's have a look at what happens. It's a bit slow. Sorry because of my poor Internet. But you'll soon see that we go to the checkout page on the Hydrogen shop. If we show the order summary, this should match with the selection in our cart. There you go, guys. That's how simple or not simple it is. It's a lot of code to write but there's a lot of functionality that the Shopify Hydrogen framework takes care of for us. We don't need to put any special code in our Checkout button. We can just bring in the Checkout URL. We can use components like this. All we have to do is put in CartCost and it figures the rest out for us. These amazing CartLineQuantityAdjust buttons, the CartQuantity itself, it's actually quite awesome how much functionality some of these components give us out of the box. One of the final things I want to do here is put an indicator of how many items are in the cart up here. What I'm going to do is in our layouts components, where is it? Right here. I'm going to insert something called a CartBubble. This is going to be a component that I built myself. Then I'm going to, underneath here, create this CartBubble component. Actually, because we're going to be using use cart, I'm going to move this into its own clients component file. I'm going to go into a new file, CartBubble.client.jsx; put that in here, do an export default. Then going back to the layout.server.jsx file, I will import that component, CartBubble and the rest is auto filled for me. If I go back to CartBubble.client.jsx, obviously we need to return something here; return some jsx. All we're looking for here is the quantity. That's all this is doing. I'm going to import the useCart hook from the Hydrogen framework. I'm going to pull off total quantity off of the object that this hook returns. This is an easy way to get our total quantity. If total quantity is less than one, which is basically zero, I'm going to return null, so basically return nothing. But if it gets past that, we will return a span, and inside the span we'll do brackets, and inside of those brackets we'll just return the total quantity. If I save that, refresh over here or refresh anywhere on our app. We've got a bit of an error, invalid DOM colSpan. We need to use camelCase for the colSpan here. Where was I? CartPage. We need to put in a capital S here. That's a weird jsx thing. What else have we got here? If we read the error message, it seems to be coming from our CartPage component. Let me just go to another page on our website and confirm that it is isolated to the CartPage. Yes, it is. If we look over here, next to this cart icon, it should indicate how many items are in the cart. Let me go over here to CartBubble. If there are zero items in the cart, it should return null, so there'll be nothing showing up. So this is suggesting that there's zero items in the cart. Let's click on the cart again, and it just returns, no items are currently in the cart. If I refresh do I get the same error? Yes. If I navigate through the CartPage from another page, it'll be fine. But if I arrive directly on the CartPage, I will get this error. I think the issue here goes back to if we go to the CartPage. This rendering without the asynchronous request to the storefront API returning yet. Having Suspense here should check for that. But in this case, it's not working. I'm going to put this return statement. This might be a bit of a hack solution but it should work. I'm going to paste it in here. If lines.length is more than zero, then let's render the cart. If I refresh over here, that solves our issue. Somehow we've lost our items in the cart but that's all good. Let's go back to our catalog or any collection. Make a product selection, and then I'll click, add that to the cart. Now, you can see our CartBubble is working. We've got one item in our cart, and if I click over to it, you'll see that this is our Hydrogen snowboard. If I add a second one, you'll see this number goes up as well. If I add a different snowboard, maybe this full-stack one, click "Add to cart" you'll see that that gets added as well. If we go in here, you can see the three snowboards that we have in our cart. There you have it, guys. If we run through our projects so far, we've got our homepage. Obviously, we haven't built anything here. This is for you guys to figure out what you want to put on your homepage. You can bring in a certain collection and feature it in all ways. We've then got our catalog page here, which lists the first nine products in our store regardless of what collection they're in. If we click on any of these, it'll go to that product. Similarly, if we go to a specific collection like the freestyle collection, and then we click on one of these product pages, we can make a variant selection, add that to the cart. Go over to the cart here. As you can see, it's saved that selection. I can increase the selection. I can remove it from the cart by bringing this all the way down to zero, and then I'll say no items currently in the cart, or if I am to add another product to the cart again, add this 154-centimeter one and increase the quantity, you'll see it increases over here as well. An improvement for this app would be to work on the loading states and build in something a little bit nicer for a suspense. Right now we don't have any fall backs, but you could build in some pretty nice loading states here. We can also, obviously, checkout by clicking this button right here, and that'll take our selection straight to the checkout. At this point, we are leaving our app and going straight to the checkout page as hosted on the Shopify store. Here we go. We can also remove that item by pressing that button. As you can see here, it takes a bit of time to build out the CartPage, but the cart functions are pretty well handled by all of these components and hooks that are available within the Shopify Hydrogen library. To summarize everything we've done in this project, I want to highlight the themes I highlighted at the start of this class before we even go into the practical side of things. If we go back to what's a simple one here, all of these have turned out quite built out in the end. But for instance, we've got a product grid item, for instance, is a client-side component that we pass in a product. If we have a look at our collection routes, we are making a request to the storefront API, grabbing all the information we need via a query, passing that into each of these product card components, and using hooks along the way. If you're ever lost or confused, you can look up any of these hooks or components in the documentation. If you're importing from React, you want to look in the React documentation. If you're importing from Hydrogen, you want to look at the Hydrogen documentation. You can literally just go over to the Hydrogen documentation. This is the storefront API one. But I should be able to search from here, UseRouteParams, go into API Hydrogen, click on here, and you can learn more about all the different hooks and components that we used in this class. In the next video, I'm going to show you how to deploy this app to your Shopify store. That's going to involve connecting to the storefront API. So I'll update our credentials here, and then we will publish this live on your Shopify store. Obviously, a lot of improvements we can make here. I've left this third link here, and that's going to be for the bonus video where we're going to add in a blog. But for now, these are the main components you need in order to have a working Shopify storefront. In the next video, we're going to deploy this to our Shopify store. I will see you in that one. 13. Deploying our Custom Storefront: Welcome back guys in this lesson we're going to learn how to deploy our Shopify hydrogen storefront to oxygen, which is the hosting platform provided by Shopify, which we can access directly on our Shopify store via the hydrogen sales channel. Unfortunately, at the time of recording, oxygen is only available to Shopify Plus plans. But if you're watching this well into the future, it might already be available for other Shopify plans. This is a pretty brand new feature, so I guess they're just rolling it out in Shopify Plus stores as they are the highest paying tier, we'll get priority on this brand new feature. Unfortunately, if you come to this page on the documentation and this warning is still here, if you're on anything under Shopify Plus, then unfortunately we are, this is not going to apply to you. You have to use a different hosting solution if you decide to deploy a hydrogen storefront. Now, lucky for me, Shopify have enabled me a store with a hydrogen sales channels, so I can demonstrate this feature. But I just want to show you on some stores, you're not going to be able to access this. For instance, on my original testing shop, Chris testing shop. If I go here into sales channels and then I click all recommended sales channels. Rounds here is where the button to install hydrogen would live if I was on Shopify Plus, or in the case of this store, have it enabled by Shopify. Unfortunately, on this store, I cannot add it, but like I mentioned here on Chris testing shop 2, which is a store I set up specifically for hydrogen. If I click into sales channels and go into recommended sales channels, it won't show up here anymore because it's already installed. But before I installed it, it was available to add here. Now you can see I've got a hydrogen sales channel right here. If you're on Shopify Plus, you should be able to go into sales channels, recommended sales channels, and add it here, then you will have this menu item here. Unfortunately, if you are everyone else at the time of recording, then you're not going to be able to do this. I'll close this one down we can't do any hydrogen there. Let me go into the hydrogen sales channel. Now what we can do is head back to the documentation and follow along. I did this and I ran into a few hiccups. What I've done is I've figured out what works and I'm just going to show you that in this video. If I head back over here to my hydrogen sales channel right here, you can see I got a hydrogen test here, but what we're going to do is create a new storefront. First of all, I want to switch back to my code editor here, and I want to make a few changes. First of all, I want to make a production branch, and that's the branch that we're going to deploy to our Shopify store. I'm going to go into here, create new branch, call this branch production. Then the next thing we're going to want to do is change these credentials to our actual Shopify hydrogen storefront. The usual way of going about this is to look into our private apps, which currently sits in settings, apps, and sales channels. Then over here to develop apps. As you can see here, I've got storefront API access as a custom app. I'll just demonstrate this quickly, I'll create an app and I'll say storefront API access. Then I'll just put Skillshare here to differentiate it. Hit "Create app". Then I'll just need to click here to configure storefront API scopes. I'll just check every box here. Then I can click the green save button. After I do that, I can click "install app", click "Install". Then here under API credentials, I'll have my storefront API access token so I can take that and put that in here. But what's going to happen when we deploy our hydrogen sales channel is will automatically get a storefront API access token. I'll show you that right now if we go into the hydrogen sales channel, click "Create storefront". Here is where we can create a brand-new hydrogen repository. I'm not going to do that. I'm going to connect an existing repository because we have, of course, got our project on GitHub already. I'm going to click "Connect" an existing repository, select "My account" and then find that repository under hydrogen class storefront. Now, something to note here is that you will need to set up the integration to GitHub. I've already done that, therefore, this is showing up with no warnings. But if you haven't, and I'll put a screenshot on your screen right now so you can see there is a warning box that shows up asking for permissions. You will need to install the Shopify GitHub app onto your GitHub account and then enable certain permissions for those guys who have been using the GitHub integration with theme development, it's the exact same Shopify GitHub app. It just requires a few extra permissions. Once you've enabled the app and given those permissions, then you'll be able to look up your repository and click this green button for Connect. Now before we do that, I just want to make note of the production branch has to be master or main. It's really annoying for me because I like to have the production branch be a separate branch called production. But by default here on hydrogen and they don't let you change it at present, it's going to automatically select the master branch or I think the main branch if you don't have a master branch as your production branch. If you do have the production version of your app on your master or main branch, then this is going to be quite easy for you. But for me liking my production branch, on a separate branch called production, there's going to be a few extra steps here. Take note of that. I'm going to now hit the green Connect button and it's going to load up this new hydrogen storefront. As you can see here, we just got a new storefront. It's just called hydrogen class storefront. As you can see down here, a preview branch is being deployed. I'll just wait for that to finish and then we'll take a look. That's finished now, and if I click on this preview URL, you will see that the master branch is deploying and it's pulling in my actual storefront credentials. The actual name of this store, not the name of the Shopify preview. Now a few things happen behind the scenes there that I want to mention here. If we go into this right here, you can see that it added a special file called a Shopify oxygen deployment workflow file. It did that through the.github slash workflows folder. This is important because it's required in order for these branches to deploy. If we go back here and we look in production, there are no deployments. If I go into all deployments here, you'll see there's nothing under production, there is something under preview. Then if I go into storefront settings, you can see there is a production branch here, but if I click on it, we're going to get a 404 page. Now, like I said, I don't like to have my production branch on master, so I'm going to create another production environment. But first of all, I'm going to update and publish this production branch to our GitHub account so we can actually connect it. Now, like I mentioned before, this hydrogen storefront is going to generate us a storefront API token. We can use that rather than creating a private app. What I'm going to do is replace the storefront token here with the one inside of our storefront settings. Then, of course, the store domain is going to be Chris-testing-shop-2.myshopify.com. Unfortunately, I can't copy it directly, so I'll just type it in. I'll just copy that and make sure that works. Yeah, that is the right address. Sweet, so we've updated our permissions here, and I'll hit "Save" on that and then I will commit those changes obviously. Stage, Update Hydrogen config file will be the commit message and then I'll hit "Commit". Then I'll click here to publish. Now that I've pushed that branch and it's on our GitHub account, I can go to "Add environment". I'm going to select the production branch. There we go and I'm going to call this production, production just to differentiate it from the other production branch. Unfortunately, I can't rename the other ones. This one is just going to be production and in brackets production because that's the name of the actual branch. I'm going to make this public and I'm going to hit "Save". Now if I go back, you can see we have a second environment here. But if I click on the URL, we're going to get the same problem, this 404 error. The reason why is it's not actually deploying. If I go back here and go to all deployments, you'll see here under preview we have a deployment. Under production, no deployment, and under our custom production deployment or environment, there is no deployment. Now what's the difference between these and this one is that Shopify added this Oxygen deployment workflow file. We're going to do that for ourselves as well. What I'm going to do is head to my GitHub repository. Here it is, christopherdodd/ hydrogen class storefront. Just to be clear guys, this is my repository, so I have access to this and I'm able to create a production branch on here for you, you'll want to make a fork or another repository and create a production branch on that. This is not the literal GitHub project that you will be deploying to your store. I just wanted to make that clear. But if we look inside here and use mine as an example, if I go here to look at the different branches, I can see one down here, they've added a new branch, and this is our preview branch. If I look inside, you can see it's based off master. But what they've done is they've added a workflow file here and this is our deployment settings right here. That's what's being served in this preview URL here. Shopify don't make this very clear, but that's essentially what's happening. What we're going to do is we're going to take this file. We just need to make note of the path here. It's.gitthub/workflows and then we put this file in. I'm going to click here to get the raw file. What I'm going to do is slightly off screen. I'm going to go into the file menu. Click "Save Page as". Then inside our storefront project here, I'm going to copy the path which was to create a.gitthub folder. It's going to warn us that dots are reserved for the system, which means that we won't be able to see this folder in our finder, or I guess it's Windows Explorer on Windows. But we will be able to see it in our code editor. Then I'm going to create the work flows folder and then in here I can save that deployment file. I'll exit out of that. Let's head back over to this and then if I go into my code editor here, you can see that change coming through. If I go over here to the Explorer, you can see that we've added that file to this path. All we have to do is commit that. I'm going to stage that add oxygen deployment file. I'll hit "Commit". I will push that change to the production branch. Once that's pushed, if we go over here back to our deployments and we go under production production, you can see that something is deploying right now. If I go into all, you can see that we're adding our oxygen deployment file to our production branch right here. I'll just wait for that to finish deploying and now you can see that it has successfully deployed and if I click on this URL here, long behold, here is our app. If I go into the catalog page, you can see that this is working just like we had it locally. I can go into any one of these surfboards or snowboards rather, add to cart, go into my cart page and check out. That will take us to our actual stores checkout. Regardless of whether you want to deploy it on the master branch or not, you're still going to need to add that oxygen deployment file in order to get that branch to deploy. Here you can see I've created a custom environment now using the production branch and we can access this public URL, which is really cool. If we want that for the master branch, we can do that as well. Otherwise, we have this preview URL here and that shows us what exactly is required by Shopify in order to get this to properly deploy. As you can see, this is not coming up under the production heading because it assumes that the master branch is going to go into the production environment. But for me, I prefer to have a separate branch because the master branch might be deploying to different stores so I often have different production branches for different stores. But there is of course some common code that goes in-between stores when I'm working with clients. That's why I like to have master branch as the common code that goes across all production branches and then have a separate production branch for each store. That's a little explanation of why I use production as my production branch. But for some reason, Shopify assumes master as the production branch. There you go. Now we have our production environment and our public URL for our Hydrogen storefront. Now that we know how to deploy our storefront to oxygen, if we're on Shopify Plus or any of the other plans that hopefully it will be available in future. Now, let's move on to the bonus lesson. We'll take a step back, build upon what we've already created and add in a blog. I'll see you in the next video. 14. Bonus: Adding a Blog section: All right, so as I often do in my Skillshare classes, I have thrown in a final bonus video, which is not essential as we saw before we have already created collections, products and enabled cart functionality, which is really all we need to create a basic functioning store. But in order to gain more practice with the workflow in Hydrogen, I am going to show you how to create a blog setup here as well so we can pull in blog posts from the store as well. What I've done is I created a production branch last time, but I've gone back to the old Hydrogen config, so we're using the blog posts from the Hydrogen preview again, this is going to be following on from two videos ago, not the last video I just needed to make reference to that. We are running Hydrogen preview, not connecting to my particular store. What we want to do is number 1, create a blog layout, and then number 2 is create a route for all the different articles within that blog post. Let me just open up GraphiQL again because I just want to verify that we do have blogs on this particular Shopify store, so I'll do blogs, this will list our blogs and I'll do nodes and handles. If I run this, you must provide at least first or last, so let's just say the first five blogs, there shouldn't be more than five blogs surely. There's two blogs on the Shopify hydrogen example store, and that's news and journal. This will work, so if we head back here, what I'm going to do is head back into our project here and let's create a blog route. Inside of our routes folder here, new file blog dot server, actually sorry, I need to make that a capital blog dot server dot JSX. Then we're going to export defaults function blog, and then return some JSX. Don't hit "Save" yet because it's got an error because we don't have any JSX in there. Then let's import some of the things that we're going to need to use, we're going to need to, of course use the use shop query, because we're going to be querying the storefront API to get the blog post information. I'm going to import CacheLong and GQL, again don't hit "Save" yet because it'll break and then I'll import suspense from react, I'll import layout from our components layout dot server and that's what I'll do for now. What I'll do is let's just test out a query over here in our GraphiQL, so I'm going to access the journal blog so let's create a named query I'm going to name this query articles, and then we can access the blog via its handle which as we can see here we've got two options to choose from, journal or news, let's do journal and then within here, let's access sorry, articles, skipping ahead a bit there. We need to put in the parameter here so let's go for the first nine, and let's type in nodes here and then on nodes we can select the title of each article, the handle of each article we'll need that for navigation and then the image, so the URL and alt text. That's all we should need if I hit "Run" on that, you'll see we get back the first 1,2,3,4 so there's only four articles, even though we specified nine if there's less than nine, that's what we get back. But the good news is that all worked so let's go back to our project over here, and I will create this query, const query equals GQL and then let's paste the query in here, I'll just leave the indenting like that and I was an idiot and hit "Save" without putting anything in our return statement so we're going to have to restart our server that's no biggie. Before we do that however, I am going to use the use shop query hook so I'm going to grab the data from use shop query, parsing the query like such, use cachelong, like we've done previously, preload true and then under here, I'm going to do const. Actually before I do that, before I do structure let's do what we usually do and have a look at that data object. I just need to put some form of JSX in here otherwise, the server is not going to run, so I'll just do that and then let's do npm run dev down here, so that's up and running now, let's refresh and let's go to our blog route, we've got an issue here, no Shopify context found this sounds like one of those weird errors that we can fix using yarn dev dash dash force, refresh and as you can see that removed all the errors. What we're looking for though, is what's in the data object and as you can see here inside the data objects we've got data again, we've got blog again, and then we've got articles which holds an object, so let's destructure here, so we'll go const from the data we're going to go inside, access the data, then inside the data, access the blog as blog. Then what we can do is let's just console log blog, make sure we got the right one. If we look inside here, you can see yet we've got articles and inside articles we've got a list of nodes cool. What we'll do is we could go in here and put the title of the blog but we're not going to in this particular video, actually all we're using this for is to grab the articles so I'm going to go one step deeper into structuring and grab the articles, actually I don't think we need to put the colon in there and then if I just console log again, you don't need to do these console logs I'm just verifying that I've got the right data here. Here you can see yeah, you've got the list of nodes right here. Actually let's go in and go nodes articles, refresh over here and now that removes nodes from the front, so we've only got articles, we've got an array of just article objects. That's all we're after let's go and put in as our parent component here, the layout we've already imported it from where it exists and then because we're accessing asynchronous data, let's put in a suspense, I'm going to put this all into a container and then I've already set up a class for the article grid which is going to be very similar to the product grid and then very similarly to the product grid, I'm going to run through all the articles, run map on that and then for each article, open up this return and we don't need to put the return in here, I think we can just put in a div here, put in some JSX here, and let's return the article title. Here we go and we have access to the article title here, so if I hit "Save" on that, refresh over here, nothing is coming through at present, let's have a look. The article grid is coming through, but not the article title here, and maybe I shouldn't have put this there. Let's do that see what happens, Yeah, so there you go we've got four divs here with all of the titles. We could do that list like I showed you before, but we're going to turn these into grids very soon so let's just leave them as divs. I can create a separate component in my components folder over here, but I'm only going to use this on this particular blog route, so I'm going to just put it below, and I'm going to call it Article grid item and I'm going to pass through the article as a prop, and then let's return the exact same JSX as we do have here, and then so I'm going to replace here with article grid item. Then the only thing we need to do is pass through the article as a prop and that's going to pass that right into here, which we can then use within our JSX down here. Hit Save on that and we should get the same result, which we do. What I'm going to do is add this class here to enable this to use our CSS article grid item is the class name. Then we're going to insert two links here. One an image link and one a link of the title. Have we imported link and image? No, we haven't. Let's import link and image from hydrogen. Then I'm going to put a link component here. I'm going to add in string here. We're going to nest the article within a blog route. Like we did with products, use the articles handle as its URL. We'll set up that route in just a second. I'm going to give that a class name of image container. Then inside here, let's set up our image component. All we need to do is pass through the article image and Shopify's image component will handle the rest apart from alt, which we need to put through right here, article, image, alt, text. Cool. We don't want it to close like that, we want it to be self closing. Sweep. Let's just see if that works. Yep, we've got these images coming through. Beautiful. Here, I'm going to create another link component, linking to the same place. I'm going to give this a class name for the CSS of article-grid-item-title. Let's close this, so we can see. Close that and then put the article title in-between these link tags. Save that and hallelujah, we've got our article grid here. If I click on one of these, it's going to just basically go to a blank page because we haven't set up that route yet. Let's set that up right now. Just like we did with collections and products, we just need to create a new folder called blog. Then just like we did with collections and products, set up a dynamic route [handle].server.jsx. Here is where we'll do the bulk of our work for this lesson. Let's export a default function. We're going to call this component article and we'll pass through the article as a prop. In our return statement here, I'm just going to output our layout file and then we'll figure out what to put inside that in a bit. We need to import some things here. I'm going to expand this out into multiple lines like we've done throughout this class and import a few things from the Shopify hydrogen library. I'm going to need to useShopQuery. I'm going to need useLocalization. I'm going to grab the SEO component because what's the point of having a good article if it's not search engine optimized. I'm going to grab the GQL and I'm going to grab the image component. I'm also going to import suspense from react and import the layouts components of course. I think we need to go back twice, going to components and then layout.server. There we go. Next thing we're going to build the query. Let's do that in the graphical interface, so we can fix up any errors before we actually run it. We also take advantage of the auto complete doing it this way. I'm going to get rid of that old one and let's just call this query article singular. Before we open that up, actually we need to pass in what variable we're going to pass in? We need to say that we're going to be passing in a variable called handle, that is the type of string. Then we're going to target the specific blog of journal. Then what we need to do is specify an article by handle. It's not called article for some reason, it's called articleByHandle. That's pretty specific, but obviously we're going to put in as the parameter our handle. Open that up and then in here, what are some of the things that we're going to need to retrieve from each article. Obviously the title, the date it was published at, the author which is now authorV2. Which is actually a selection, we just need to specify what we want on that selection. I just want the name and then image, which is obviously a selection. We're going to grab the URL and the alt text and then the content HTML, which is the contents of the article. Obviously this is not going to work because we haven't specified the value of the handle, but at least we have used graphical to help us auto complete some of these fields. Let's go back here. I'm just going to write down here query as a constant GQL, open this up and then here we go. We have hard-coded the fact that we're looking inside journal, but the handle we're going to pass in as a variable. Inside of here we can grab the handle that we're looking for through the parameters, through the props of this component. I'm going to grab the handle off the article and then let's useShopQuery, so const data equals useShopQuery. This time I'm just going to put in the query and the variables. The variables that we're going to pass through is simply the handle. Like I always do, I'm going to console log the data that's returned from our query. When we go to one of these, we've got an error, cannot destructure property handle of article as it is undefined. We don't actually have access to an article object here. Let's have a look. We're using the wrong thing here. We need to useRouteParams. Sorry about that. UseRouteParams. We not going to pass it through, we're just going to use the RouteParams. I'm going to useRouteParams here and pull off the handle. Let's refresh. Oops. Let's go back to our blog. Click on one of these. Now we've got an error from the Storefront API, the variable handle was provided invalid. It's probably because I didn't use the brackets here to invoke it. Let's refresh over here. Yes. Now we get no errors. Let me have a look here. We scroll down. There we go. We're getting the console log of data here and it's giving us back data blog article by handle and then object inside there. We can actually just copy this and use this for our destructuring. Obviously we don't need to use object here, but we can pull off the article by handle and then our console log the article by handle. Refresh over here. If I open this up, you'll see we've got this object come through title, publishedAt, authorV2, image and the content of it. Very cool. That's working now, our Storefront API query. Now we have this thing called articleByHandle. I don't really like articleByHandles, so I'm just going to swap that. I'm just going to call it an article. I don't know why it needs to be articleByHandle. Then we'll use article within here. What I'm going to do is, I'm going to open up a suspense for the SEO component let's say type article and then the data is just going to be the article. I want to make that a self-closing tag. Then after that what we're going to do is create this article page, so I'm going to create a dev with the class of article, page, and container. Then I'm going to have two parts to this. I'm going to have the article page header and then the article itself, article page header is the class name. I'm going to put through H1, the article title. I'm going to create a span here for the date which we still need to format it. But let's just say it's article. Let's just put through the unformatted one for now. PublishedAt, we'll separate that with a dot and put the article authorV2.name here for the author name, and then after the header, we will create, open up an article HTML tag in here is where we'll put our main article image. I'm going to pass through the article.image, and then in the alt texts, the article image, alt text. Self-closing tag for the image, and then what we're going to do is the div for bringing in the HTML. We're going to see this dangerouslySetInnerHTML attribute again, and we just need to do this underscore, underscore HTML equals and then not equals colon rather. Then put in content HTML coming from the article object, and then I'm going to give that a class name for formatting of article body. Cool. Let's wrap up that div, and let's see what happens now when we run this page. Look at this. We've got the title, we've got the date which we still need to format. We've got the full name of the author, and then we've got this image here, which is the main image. If I close this up, you can see that's the first part and then the content of the article. This is pretty much done. The only thing we really need to do is fix up this timestamp here. It's pretty **** ugly. Obviously we can't leave it like that for the user, and also in case there is no article, I want to put in a fallback as well. Let me do that first. I'm just going to put it in a fallback. If there is no article, then let's return with our layout components. Still using the container. We'll just put in a div with article not found, and that also reminds me to build in something to our app component that I mentioned in the theory lessons, but I haven't implemented in this particular project which is bringing in the routes component and doing a NotFound route. We can use this wildcard selected here. Anything that slips through file routes and makes it to here, we'll just bring in a NotFound components. Sorry, this is quite the tangent, but I just thought of it then when I was creating that fallback for the article page, and then underneath here, actually let's do it here. Function NotFound. This is just a little 404 page return without layout, which I believe we will have to import layout from components, layout.server. Then just like we did for the article page, a container with a div inside that just says page not found. Now if I go to an article that's not found, so our hello, Let's just put in something random like that. It'll come back article not found. If we go on the root route and type in something random like hello there, it will say page not found. That's a little bonus for you there. Let's actually update link 3. I'm bouncing around a little bit here, but it is the bonus video. Give me some slack guys. In layout.server, let's put in a link to the blog. Get rid of that ugly link 3, and then if I click "Blog", it's going to take us to the blog, and then if I click here, we'll get to one of our articles, and so yeah. Like I was saying before I went off on that tangent, we need to format this date, which is a little bit more complicated than we would like, but we are bringing in, use localization here, which is a hydrogen hook. We can use the structuring to pull off some things here from the use localization hook. What we're going to pull off is language, IsoCode. LanguageCode is what we're going to call it, and then country will bring off the isoCode of the country and bring that into its own variable called countryCode. This is going to be for the next function we use. We're going to create a formatted date, and we're going to create a new international date time format objects. This is a specification within JavaScript. This is not react or hydrogen. Then we'll open up a string here, putting in those two variables that we've just created that we've just pulled off of use localization. The first one languageCode, then dash countryCode, and then the next argument will go and put in an object year numeric, month long, and day numeric. This is all up to you personal preference. But we're going to have a numeric year, a long display for month, which I think just does like if it's January, it's going to output January completely, and then day is going to be numeric as well, which makes sense. Then after here, we're going to run formats on that newly created object and then run it through a new object, article.publishedAt. That looks pretty hectic, but basically we are just converting that publishedAt date into this international date format. Now that we have this formatted date, we can just go down here and replace article publishedAt with the formatted date, and unless we've made some errors here, which it looks like we have. What have we done? Cannot access article before initialization. I have made the article variable after I have written all this code, so I just needed to move it before, and then if I hit Save on that refresh over here you can see the long form name of the month, which is June 3, 2022 from Ben cell or however you pronounce his name, and there's your article. If we go to other articles in this blog, you'll see it works just as well. That's a little bonus for you guys. The blog page, I feel like this lesson should be pretty good practice for you guys because like I mentioned earlier, we're running through like just a sequence over and over again of building these components, grabbing data from the storefront API using used sharp query to grab the data that we want within that returned data and then use it within our component. Then at the same time, bringing in some of these other components and hooks from Shopify, which make our lives so much easier. That basically concludes this class guys. I hope you enjoyed it. Any questions as always leave them below, but let's jump into the conclusion now where we'll talk about your class project. I'll see you there. 15. Conclusion & Class Project: This concludes this class on Shopify hydrogen. For your class project, I encourage you to create your own custom storefront using hydrogen. For inspiration, you can take what we've done so far in this class and expand upon it. You could build a product gallery to bring in more product photos from the backend, create a drawer to house the user's cart without having them leave the product page, or build custom sections to showcase your product's best features. The choice is yours. As always, if you have any questions or concerns, leave a comment in the discussion box below, and I'll do my best to point you in the right direction. Thanks as always, for watching and I hope to see you again on some of my other classes.