React Order App: A Beginner's Guide | React Project | App UI & Shopping Cart

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Hello everyone, and welcome to another React video. Today's video is going to be very interesting, where I’m going to build a drink-ordering app project. It’s a beginner project where you’ll use React’s key features and hooks to create UI and cart functionality from scratch. If you're new, please subscribe and press the bell icon so you won’t miss any tutorials in the React series. Let's get started. This is the project we’re going to build through this video, Here we are rendering dummy data, and each drink card has an add-to-cart button, We can increase and decrease quantity of each one, and when we click this add button it’s going to update the number in cart. If I increase the quantity of this drink and click the add button, you’ll see the product has been added to the cart and updated badge number. Now when I click this cart button, cart container is going to appear, which contains the product information and total price. Now if I increase the quantity, you’ll see total price get updated, and if I decrease the quantity, the total price gets reduced by price. If cart has only one drink item, then decreasing the quantity will delete that product. Let’s start building. Open your favorite code editor mine is VS Code and open terminal and type npx create-react-app and then folder name, I'll name my folder 'refreshCall' and now press enter. It’s going to install all necessary files that we need for our new react app. When you are done with installing, you will see that the React project has been installed with the folder name refreshCall or whatever you gave it earlier. Now, lets navigate to this folder with the command cd and project folder name refreshcall / now press enter Now go ahead and type npm start. Here we are, we successfully installed React on our local server. Now let’s go to our project folder and there we’ll delete unnecessary files that we won’t use. So I will delete App.test and reportwebvitals file as well and inside the index file remove here, here and also this. Now In the App js file, you will notice some default code, let's remove and replace with our own. And also I’ll delete these import line as well. Also you can select font-family that you want to use in your project from google fonts. I chose Nunito, and from here you can copy the link and go to the index.js file which is inside the public folder, where you can paste it inside the head tag. Let’s use style tag and select the selector to declare font-family and margin, margin is 0 and copy font family and paste it here. Also we can change title so I’ll change it to my app name refreshcall. Now we are ready to work on our application. Let’s create a Header, In src folder, create a new folder called components, and inside this folder create a subfolder called layout, and inside this folder create a file named Header.js. The components folder will have reusable components used to build UI. I am using extension ES7 React/Redux/GraphQL Install it from here if you’ve not already. It’s going to help you building the app very fastly. Now inside Header component, you can use shortcut rafce and it’ll create an arrow function with name Header and export it as default. Now we can import this component into App.So import Header from layout folder also return Header element within div tag. Now inside Header component, we’ll have a logo and a cart button where we’ll display a number of drinks in the cart. Also, I’ll include title and content. Let’s create another folder named assets, it’ll handle our application images. Inside this assets folder create img folder and save logo and banner inside. So this is banner and this is my logo of this app. Inside Header component import logo variable from our image is outside of this so I’ll go level up and assests folder and image folder and then file name refreshcall.png The return statement contains JSX code where I will structure header for symantic reason. Inside this header write navigation section using nav, inside navigation we’ll have our logo and cart button so let’s define an img tag for displaying a logo and then src attribute specifies the source of the image, which is stored in the logo variable. The alt attribute provides alternative text for the image, which is helpful for accessibility so I’ll write my app name refreshcall then close this. We’ll define our CartButton shortly. Let’s defines a div HTML element outside of this nav it will hold the main content of the header. Write h2 element for title and inside the title let’s create nested element span around refreshing, later we’ll apply the class to change its color to make it stand out. Lastly, define p a paragraph element to describe what the users can expect from the selection of drinks offered by the application. So here Header component contains navigation and content section with a title and a descriptive paragraph. Let’s see, it works.Now it’s not looking what we want to so I’m going to use css for styling, I’ll use CSS module throughout the App. There are many advantages of using CSS modules. A CSS module is a simple CSS file, a technique used in React to style individual components. we just need to add .module before the .css extension to the file, for example instead of style.css, save file as style.module.css. I’ll recommend you to keep watching and you’ll understand it better. Let’s create separate CSS file for Header component, named Header.module.css and import this file to Header component as follows. Here styles is an object, Instead of styles, you can use headerStyle or any other related name. We insert classes similar to using local variables in Javascript. In header tag define className attribute and because styles is an object we’ll use curly braces and pass styles.header inside, will be responsible for styling this header section. Now inside the Header.module.css file we’ll declare styling just we used to. targets elements with the class name "header" set the maximum width of the element to be 100%, set the height of the element to 400 pixels, It determines how tall the header section will be on the page. sets the background image for the header. specifies the URL of the background image. Make sure the path is correct relative to the location of the CSS file. So it’s outside of the component and inside the assets folder and inside img folder and the name banner.jpg no-repeat, prevents the background image from repeating. center/cover, This combination centers the background image both horizontally and vertically within the element. As the module follows the rules of local scope, we can have a header class in a different component with a totally different style. Now let’s see, perfect! Now I’ll define nav-items class to style the navigation section. So display flex, justify content space between, align items center, padding 10px top and bottom 5rem left and right, Now we’ll have content class to style text. For title I’ll use different font-family so let’s go to Google Fonts and search Montserrat click to add button and now copy this import from here and paste it at the top of Header.modul.css file. Also copy this font-family and paste it here and font-size is going to 1.25rem then text align center Next define content class with p paragraph for to style font size 1rem. Here select the class .text-color to change the color of the text. The color is going to shade of purple. To use these styles in that specific element, let’s go to Header component, classes are defined in the styles object imported from the Header.module.css file. If a class is a single name, we access the selector class as `styles.header` and if it uses a hyphen like nav-items, we use a square bracket, here define class name attribute and styles and then use square brackets with single quotes then nav items. Define the class name attribute and styles object with the content class that we defined earlier and text color class, className attribute and style object and the class text-color. So here, if it’s a single word we are going to use as it is and if it’s hyphen we use square brackets. Now go to browser and here everything is good. Also here I’ll include cartButton a custom component so inside the layout folder create a new file and name it CartButton. Write rafce and press enter remove this from here we don’t need anymore with the updated version. And then return jsx with the button element And this button element will take another nested element span there we’ll include cartIcon leave it as it is for now, specify another span for badge and number is 0. Now create another new file inside layout folder named CartButton.module.css and I’ll write css code here. Import this file into Header component as follows. Now we’re applying a class using the className attribute the class will be imported from styles object . I’ll use square brackets and inside square brackets the class is going to cart-container. On span define className attribute and class is going to styles.badge, We’ve this cart-container class inside CartButton component so select this class and give the position relative, background is going to shade of blue, padding .5rem, border-radius 5px and the cursor is going to pointer. We’ve another class badge so select this class. It's likely used to style a badge element, which I’m going to use to show the number of items in a cart. For creating the circular shape, I need a fixed width and height, so width is 25px and height is 25px as well. Position is going to absolute to positions the badge absolutely within its nearest positioned ancestor, border-radius 60% this property rounds the corners of the badge to make it circular, color is white this sets the text color of the badge, sets the background shade of purple, top property is going to -12px and right is -12px as well these properties position the badge 12 pixels above and to the right of its normal position, creating an overlapping effect, display inline flex, justify content center and align items center, center the badge text both horizontally and vertically within the badge element font-size 12px and set the font-weight bold, box-shadow add the subtle box shadow to the badge, giving it a slight elevation effect. And last step we need to include CartIcon nested component inside ButtonCart component for this I’ll create another new folder inside components folder and folder name is going to cart, Inside this cart folder we’ll have our cart container and cart items. Let’s create new file, CartIcon js and define functional component CartIcon also export it as default. CartIcon returns jsx structure svg-based cart icon, you can download svg code from online and paste that code inside parenthesis. import CartIcon into this file and between span return CartIcon element also inside the Header component import CartButton and return CartButton element, … … and move CartButton component inside layout folder. Now save all of that, it's good! Now let’s create reusable drink cards where we’ll display the information for each drink, including the name, price, and quantity controls. Go to vs code create another new folder name it drinkCard and inside folder create new file called MenuItems.js Inside this file we’ll store a list of different types of drinks in a simple JSON format Define a functional component MenuItems and export it as default. Now let’s create an array of objects representing different drinks, const drinks data and the array, Each object will contain properties like id, name, description, price, and image. Let’s define our first array object with id 1, name blue lemonade, description cool and tangy delight, price 2 dollar, because I’ll have 8 drink items so copy this and paste this here 8 times. Replace the id with 2 … … now I’ll replace name blueberries smoothie and description creamy and refreshing, price is 3.5 dollar. Next name is chocolate shake, description heavenly chocolate milk shake for chocolics, price is 2.1 dollar. Remove blue, lemonade and description is going to enjoy the tangy refreshments of lemonade, name Mojito description combines the flavors with a vibrant blue color twist price 1.5 dollar, here name is goint to min tea and description naturally, sweet and free of caffeine and the price is 1.9 dollar, name raspberry smoothie and the description burst of flavors with raspberry smoothie price 2.7, and the last name is going to strawberry shake and the description is sweet creamy delight and the price 2.4 dollar. Each drink item also needs an image. Let’s save images inside assets folder. Create another new folder `drinksItem` and paste images inside. Here we’ve different images, you can get free images from pixabay and pixels. Let's import these images into MenuItems so we can access them. blueLemonade is variable name which is inside asset folder which is outside of component so level up one folder and second and then assets and drinksItem folder and file name blue lemonade, here I’ll copy this and paste it here and change the variable name to blueBerries and the file name is goint to blueberries-smoothy.jpg paste again and change the variable name with the chocolate shake and the file name and here is going to lemonade variable and change the file name to lemonade.jpg another the variable is going to mojito and the file name is mata so I’ll change it to mata as well and here I’ll change name to mata, paste again mint tea variable and change file name, again, it’s going to raspberry change the file name, another image with the name strawberry shake and change the file name as well. Inside array of object place new image property and value is going to variable that we created earlier, it’s create a reference to an imported image file. I’m going to add the image property to all of my object with the assigned variable name. Now that we have created dummy data, it is time to define a section in jsx so return, write the section element, and for styling, I will create a new file within drinksCard folser called MenuItems.module.css, and here I’ll import it into the MenuItems component. So import style object and file name is MenuItems.module.css I can now define className with a style object to access items. Here I give class items so select items class set max width 65rem and width 100%. This makes sure the element takes up the full width of its parent container display flex and grid template columns set to repeat with the value is auto-fit … 300px and 1fr, margin 1rem auto, grid gap 20px. Inside MenuItems component I’ll use map() javascript method to iterate array of drink data objects which are stored in DRINKS_DATA constant. This is javascript expression so enclose it with curly braces. Map accepts arguement so here I’ll specify drink and here just for example I’ll use paragraph and return drink.name. To display on page I’ll import MenuItems component insite the App and return, below Header element. Now Let’s see and you’ll see it displays each drink item name on page. Now I want to display a list of drink cards based on data. Go to vs code, inside drinkscard folder create new file DrinksCard.js and another file for CSS module here DrinksCard.module.css . Now we’ll import style object from the file name DrinkCard.module.css now define functional component with const DrinksCard and export it as default. remember instead of styles you can name it as you want. Import styles form DrinksCard.module.css In MenuItems component, instead of paragraph, we’ll pass nested component DrinksCard to dynamically render a DrinksCard component for each drinks. So import it at the top and here DrinkCard element. On DrinksCard component specify attribute key and value drink.id, It's required for elements rendered inside a loop or map function to help React keep track of each element uniquely. id drink.id allows the DrinksCard component to identify which drink it's rendering. Image with the value drink.image provides the image source for each card name={drink.name}, description: {drink.driscription}, price: {drink.price} And the name to display the name, description drink.description, and then price. Each card gets its unique data (id, image, name, description, price) from the corresponding drink object in the data array. Now we can access these properties from DrinksCard component. So here inside DrinkCard component pass props as an argument inside parenthesis. Return div and on div specify className attribute with style object I’ll create a module css file shortly. And here the class name is going to drink-card, I’m using hyphen so I’m using square brackets. Let’s display the drink’s image with the src attribute we’re accessing from the parent element alt attribute with the props.name and the className is going to style with the class drink-card image here another div with the className attribute with style object with the class drink-card content contains the name and description, so here h3 with the className style drink-card name and it’s going to display the drink card item name and the paragraph with the className attribute style object with class drink-card description.It’s going to display the drink description Then another div with className style object and the class is drink-card foother represents the footer section of the card, which includes the quantity controller, price, and an "Add" button. Here drink cart quantity is a placeholder for the quantity controller. Here write className style and the class is drink-card quantity and here I’ll give it a class name style object and class is price and here the className attribute and with the style object and class is going to drink-card add btn. Now let’s give our cards some styling. Let’s select drinks-card class set position relative, display flex, flex direction column, align items center, set background image for the card, creating a linear gradient from transparent to a dark blue, specify 180deg transparent dark blue, set color light gray color, add a bottom margin of 1rem, card’s width to 280px, set height auto, border-radius 8ox giving it a slightly curved appearance with 8px border radius. Border 1px solid gray color light gray, box shadow 0 5px 10px and rgb, applies the box shadow to the card, transition transform 0.3s for smooth transition effect. Now I’ll select class ‘drinks-card__image`, width 100%, height 180px, object-fit cover, object position center defines the position of the image within its container, border radius create a slightly rounder bottom right corner, giving the image a subtle stylistic effect. Now select the class `drinks-card__content`, set padding 10px and 20px. Select class `drinks-card__name`, set font size 18px, font weight 700, letter spacing 2px there will be an extra 2 pixels of space between each character in the text. Select class drinks-card__description, set font size to 14px and margin bottom 20px. Select class `drinks-card__foter`, sets the display property to flex, sets the width of the element I’m going to usecalc() function to calculate the width 100% minus 20 pixels, padding 10px, justify content space between, align items center. Select class drinks-card__quantity, sets border radius to 2px, background light gray, font size 1rem, font weight 400, color black. Select class `drinks-card__add-btn`, sets the background color a shade of purple, padding top bottom 10px right left 20px, color white, border 0, box shadow. I’ll also apply hover effects on card, transform property and translate Y with the value 10px. when you hover over a .drinks-card element, it will move 10 pixels down from its original position, creating a subtle "lifting" or "floating" effect. Save the file, let’s see our work, fantastic! This is a simple UI of drink card and to allow increasing and decreasing quantities, I’ll add button instead of text and instead of price text here I want to add actual price that we defined earlier. So let’s go to DrinksCard component and here I’ll add curly braces defined props.price, here we’re accessing the price from parent compoent MenuItems save it and let’s see and here we are. We render successfully the actual price that we defined earlier when we created dummy data. Now to add quantity controller let’s add a nested component inside DrinksCard called QuantityController.js create new file QunatityController.module.css to styling component, let’s import styles object from QuantityController.module and type rafce to automatically create arrow function and remove this, I’ll define classes with style object and later we’ll add code to module. Now in return statement I won’t use div because I don’t need wrap it within parent element and also it’ll add extra node to DOM instead you can use Fragments or empty tag, here, I’ll use Fragment and import it from react library and instead of div replace it with fragment. Now within these tags create a button element with a class name styles object quantity__btn. This button is to decrease the quantity, I’ll use minus symbol you can import icon as well. Now define an input field where the user can enter the quantity. an input of type number, set min attribute to 1 value is 1 and give it a className styles class quantity_number I’ll copy this her and use symbol plus again you can use plus icon and here we've got a div wrapper with className “drinks-card__quantity”, inside this update with the child component, so here import QuantityController from file QuantityController and return element QunatityController as well. Just like DrinksCard module let’s add some css code to QuantityController. We’ve two same classes quantity__btn and let’s select this and sets border to none remove default style and sets background color to transparent, font size, font weight 500, margin 4px and 6px, cursor posinter. Then select class quantity__number and sets display property with inline block, width of 25px, height of 100%, font size 1rem, margin 0 10px, text align center, border none, background transparent. Let’s see and exactly look like how we desired. Now I want to add logic to drink order app, when I click on plus button the number should increase and when I click on minus button the number should decrease by 1. Also I want to track the current quantity value. To handle quantity I’ll use state update logic. Because QuantityController is inside the DrinkCard component so I’ll handler logic inside the parent component, let’s component useState to update logic Import useState form react and declare const with destructuring pattern inside this specify state variable itemQuantity and state update function setItemQuanity call useState with initial value 1. Now Declare the handler for Increasing item quantity, handleQuanIncrease, inside this function we’ll pass setItemQuantity to update the quantity state. It takes the previous state prevQuant, and increment it by 1. This ensures that we're always increasing the quantity by 1. Now I’ll declare function for decreasing item quantity, so let’s const keyword handleQuanDecrease. Inside this function, first check if the current itemQuantity is greater than 1. This check ensures that we don't go below a quantity of 1 because we don't want negative quantities. If the condition is met, specify setItemQuantity again it takes previous state and then calculates the new quantity, use Math.max method and pass prevQuantt - 1 and 0, this decreases the quantity by 1 but prevents it from going below zero. Next, define a function called handleQuantityChange to handle changes in the quantity of an item. It takes an event object e as its parameter. Inside this function, pass setItemQuantity, and inside this function, pass e.target that triggered the event, in this case, an input field, value, text currently entered into the input field. Now pass these handler function to QuantityController component for this we’ll set attribute on QuantityController so set onIncrease and pass handleQuanIncrease handler inside and pass second attribute onDecrease and pass handler handleQuanDecrease handler function inside and pass another attribute onChange and pass handler handleQuanChange handler functions on it. Also I’m going to pass itemQuantity state variable to it to display the updated quantity dynamically. Here quantityNumber and item quantity as value. Now we can pass props parameter to QuantityController function and let's use those properties that we passed to our child component earlier. On minus button declare event onClick and pass handler props.onDecrease, and inside input declare event onChange and pass handler props.onChange. And the value is going to props.quantityNumber, on plus button pass event onClick event with the value props.onIncrease In browser, when I click button, the quantity increases and decreases as expected, but I also want to update this price here by quantity. So let’s go to DrinksCard component declare new const variable price and pass props.price and call javascript method toFixed() and pass value 2. This is used to format a number with a fixed number of decimal places, price.toFixed(2) formats it with two decimal places, and stores it in the price variable as a string. In the next line we’ll converts that string back into a number, declare const amount variable and use + operator before price to convert the formatted string back into a floating-point number. Now in return jxs statement instead of props.price we’ll calculate the total cost of items based on their price and quantity. Use template literal and then specify two dollar sign one for string and other to evaluate expression, specify curly braces and inside performs simple multiplication operation, amount variable multiplication operator by the itemQuantity. Save everything and let’s go to browser increase quantity and price is updating now decrease quantity the price is updating as well. Now I’ll Implement refs to track the quantity input for each drink item in the DrinksCard component. This lets you access the current quantity value when adding the item to the cart. Let’s go to DrinksCard, and beside useState import useRef another built-in hook. Inside component call useRef hook and pass initial value null. Declare a variable quantRef, that holds a reference to a DOM element. Attach this ref to an input element by passing on QuantityController. So ref and the value quantity. I’ll also update handleQuantityChange function and within function I’m going to declare a new variable updateQuantity. To ensure that quantity is represented as a number I’ll use parseInt() method and pass quantity that we defined earlier and current.value, I’ll pass updateQuantity as an argument. It sets the new quantity to the parsed integer value obtained from the input field. Here, we passed a ref to the nested component to read the input value that is contained inside the QuantityController. To pass a ref from a parent component to a child component, we need to use forwardRef method inside QuantityController component. Let’s import forwardRef function from react library. Then I’ll call forwardRef function on functional component, it accepts a render function as an argument, so wrap component into forwardRef() and close the parenthesis, it takes parameters props and ref, ref parameter is used for forwarding a ref from a parent component to this component. Now we can pass ref to the DOM node, input, to read its current value. Now we can control the quantity of items based on user input without relying solely on state updates. Now, I want to interact with the add-to-cart button; when I click it, this drink item should be added to cart, and badge should be updated with the item quantity. So in DrinksCard component, declare function using const keywords name function handleAddToCart and keep it empty for now, and pass this handler function on button, specify event onClick handler function inside curly braces. I’ll come back to this and add add-to-cart functionality in shortly. Next step is to implement shopping cart functionality into drink order app. I need cart functionality in different places, like on the product page where I’ll handle adding drinks to the cart when I click this button and inside cart component where I’ll display added products. Since we need to access the cart state and functions in various components, we’ll use React Context to manage the cart state and provide it to the components that need access to it. Create a new folder inside the src folder next to the components and name it context and create another new file inside newly created context folder called CartContext.js. Because it is not a component, you can name it whatever you want, using a small letter or a hyphen. Now, Call useContext at the top level of your component to read and subscribe to context. And , define an object with const keyword CartContext as a variable and create a new context with the method createContext, export it as the default. Context allows you to share data across the component tree without manually passing props down through each level of nesting. Inside createContext I’ll pass default value. On Cart I’ll have items to display drink information like image, price and name, total amount, and options for adding and removing items from the cart. So let’s pass object item property and empty array that will store the items in the cart, next total amount as a property 0 representing the total amount of price of items in the cart, next add the function addItem that takes an item as a parameter but does not perform any action by default it's a placeholder for the function that will be provided by the context is actually used, next pass removeItem as a placeholder that takes an id as a parameter, and another function clearItem as a default value. To pass context to components we need a provider. I’ll declare provider in a separate file, so let’s create CartProvider inside context folder where I’ll handle state. First, let’s import context into this file. Now declare an anonymous function using const keyword and component name CartProvider. Pass children, which is a special property that represents the child components that will be wrapped by this context provider. Now return CartContext.Provider element and pass children property between curly braces. To retrieve cart information for all components in the hierarchy tree, we’ll modify the App component and wrap Provider around children components. So I'll import CartProvider from context folder and CartProvider file name. And instead of div I'll wrap it with CartProvider element and also I forgot to export it so let's export default CartProvider. Now save it and you will see it is as it was before. Next step is to handle various actions like adding an item to the cart, removing an item from the cart, and clearing the cart and manage these state of the cart items I'll use useReduser. You can put all of the state update logic outside your component into a single function, called a reducer. In a CartProvider declare initial state with the const keyword and name it cartInitialState and return a stateful value. We'll return items with an empty array and total price value is 0. Write a reducer function, where you will put your state logic. So const cart reducer you can name it as you preferred, It takes two arguments, the current state and the action object, and returns the next state: Now import useReducer hook from react library. Let’s update CartProvider, inside call useReducer that we declared earlier and pass cartInitialState. It also returns stateful value and dispatch functions. Let’s use const keywords, use square brackets, and write state and dispatch. Instead of state and dispatch, you can use your preferred name like cartState and dispatchCartAction. Now I’ll declare handler function with the const keyword handleAddToCart arrow function that takes a single argument item, this item represents the product or drink that you want to add to the shopping cart. Within this function, I will use the dispatch function, which is known as an action and represents the user's intention; for example, if this event is triggered, it will send a message to reducer indicating that the user wishes to add an item to the cart. Now pass an object, type property and string ‘ADD_TO_CART’ and then additional property item and set to item argument passed to the function. Now I’ll declare another event handler so let's use const name handleRemoveItem which takes ID as an argument and within this function specify dispatch and pass object, property type string ‘REMOVE_FROM_CART’, additional property id set to id argument. I also want to clear items from my cart when clear button is clicked. I’ll declare another event handler const keyword and handleClearItem dispatch function, which only accepts property type string ‘CLEAR_CART_ITEMS’. Now on context provider, we need to specify a value attribute, which is used to provide data and functions to the components consuming this context. Now to pass these handler function handle add item, remove item and clear item I'll declare object called contextValue. Define property items and value state items, This property holds an array of items that represent the contents of the cart. such as id, name, quantity, price, Define property total and value is going to be state totalPrice, holds the total price of all the items in the cart. Now addItem another property and the function name handleAddItem, that we declared earlier as a value. removeItem property and then pass handle remove items as a value, it is called when a user wants to remove an item, These functions are responsible for dispatching an action to update the cart's state. Now clearItem as property and value handleClearItem. It's often triggered when a user wants to remove all items from the cart in one action. Now on value attribute pass contextValue object, Components that need access to the cart's data and actions can consume this context and use these properties and functions to interact with the shopping cart. Now, we’ll write state logic to reducer function. Inside use switch statement to determine how to handle different types of actions. swithch takes an argument action.type, it is a string that describes type of action being performed, then we'll have our three cases which is going to add to cart, remove from cart, and clear cart items. So implement case add to cart, case remove from cart, case clear cart items. Each case would depend on the specific requirements and structure of cart state. Now I'll return default of switch statement it returns current state if action type doesn’t match any of defined cases. Now we'll fill the code and work with these case one by one. I'll start with the add to cart. First, I want to see if the item already exists in the cart; if so, I will update the quantity; if not, I will add a new item to the cart. I'll Destructure the properties of the action item id, price, quantity from action item Now I'll heck if the item already exists in the cart. So let’s const keyword with the name existingCartItem state items find, it search for an item in state items array with same id, pass items as an argument item id match with id action id. Now in the next line I’ll calculate the new total price, use const keyword with cartItemsTotal name and state totalPrice plus item price and multiple by its quantity, update the current state of total price by item price by its quantity. Now If the item already exists in the cart I’ll increment its quantity. Let’s use if and pass existingCartItem in the parenthesis use const keyword with the name cartItems then state.items, I’ll use map method and give an item as an argument then check if current item, item id, being processed has same id as item you are trying to add. If it does, it returns a new object copy of the items, quantity item.quantity plus quantity, where it increments the quantity property by the specified quantity. Now I’ll return an item and then we’ll update the state of items and totalPrice so return a new state object, use spread operate which create a copy of current state object then items property with new cartItems array, updating the cart state with the updated item quantities and set totalPrice property to cartItemsTotal But If the item doesn't exist in the cart I’ll add it. So here use const keyword with the name updatedCartItems spread operator state.items and action items. Action item represents the item that you want to add to the cart. And the next return state items property value updatedCartItems property totalPrice cartItemsTotal. Now to remove a drink item from the cart, I’ll update the REMOVE_FROM_CART action in the reducer method. Let’s start by finding cart item I want to remove from cart. Use const keyword with the cartItem then state items find pass item as an argument then item.id match it with action.id now then define updatedTotalPrice and calculate it by subtracting the current total price from the cart item price. So here state totalPrice minus cartItem price. Now let’s move to next part. We’ll check if item exist in cart and also check quantity is greater than 1. If condition is met, create a new array. Define updatedItems with the const keyword then state items use map method on it that takes item as an argument. And for each item in the state.items array, check if id matches action id and If it's a match, create a new object item quantity and reduce quantity by 1. This effectively decrements the quantity of the matched item, then return item. Finally, you can return a new state object and items updated to updatedItems and the totalPrice updated to updatedTotalPrice. But if quantity is 1 it should be removed from the cart, so here I’ll write else statement, create another new const give it name updatedItems state.items and call filter method on it, state items as an argument item.id and we’ll filters out the item with the matching id. Finally, return a new state object spread operator items updated to updatedItems and the totalPrice updated to updatedTotalPrice. Now, I’ll handle action type 'CLEAR_CART_ITEMS'. Let’s return, new state object using spread operator to ensure that you maintain the current state properties that are not being changed. Set items property to an empty array, this effectively removes all the items from the cart, making it empty. Set totalPrice property to 0, This ensures that the total price is reset to zero because there are no items in the cart. In shopping cart I’ll check if blueLemonade already exist and if it does then it’ll only increment its quantity I’ll change it to 1 to 2 and 3 and we won’t add it as a new product. It looks good, but, how would I know if this code works? let’s implement add-to-cart functionality. We’re using context for state management, and context provides access to cart-related functionality, Inside DrinksCard I’ll use useContext hook to access cartContext, import it at the top CartContext which is inside the context folder and beside useState and useRef import useContext as well. Then call useContext inside functional component and pass cartContext inside parenthesis. Let’s assign contextItems variable to it. To allow us to add drinks to the cart, we need to handle Add to Cart button click event. Let’s create object named item and extract product properties, so here id with props.id, image props.image, name props.name, and price I’m going to pass amount as a value so here we are. Also, I want to include quantity in this object so let’s extract the quantity value from a ref, so here use const with the quantity and parse it as an iteger.so here parseInt parenthesis quantRef.current.value. Now pass quantity property with quantity value, this is done to get the quantity of the item that the user wants to add to the cart. Now you can use console log and pass item you’ll see selected drink item information logging into console. Finally, call addItem function from the contextItems object (which is the context provided by CartContext), and pass the item object as a parameter to this function. handleAddToCart uses this functionality to update the cart with the selected item and quantity. Now whenever we click this Add button, it’ll trigger the dispatch action and update context. Now, I’ve a button component that serves as a cart button. it displays a cart icon and number which is hard coded and I want to dynamically update badge with the total quantity of items in the cart. Let’s go to CartButton component. You can access the cart state from the CartContext and calculate the total count of items to display the badge. Also import useContent hook and call useContent inside CartButton functional componentaccess the data provided by the CartContext Here I’ll declare variable cartValue with const keyword. Now I’ll use reduce method on cartValue.items array to calculates the total quantity of items in the cart. Declare new const variable totalQuantity, accesses the items property from the cartValue object.. Apply reduce, which is a Javascript method, used for aggregating data in an array into a single value. Pass callback function to reduce method. It takes two parameters, total and item, total is an accumulator variable that keeps track of the total quantity, and item represents an individual item in items array. Now return and in return statement, add up total + item quantity, and after comma pass initial value 0. In each iteration, this line adds the quantity property of the current item to the total. And totalQuantity will contain the total quantity of items in the cart. Now in span element, I’ll pass this variable to display the cart's total quantity in the badge on the cart button. Let’s see, click on add button and it goes up; add another drink and badge is updated. Good! Now let’s build cart container to display items in the cart, their quantities, prices, and total price. Inside cart folder create a new file called Cart.js and create another file named Cart.module.css. Inside Cart component I’ll import css module so import styles from Cart.module.css which is in the same folder. And here I’m gonna use styles object inside className and later I’ll write code for css styling. Now define Cart component, it receives props and export it as default. This component will use the cart state from the CartContext so import it, import CartContext from context folder which is outside of component. Now use useContext from react library as well to access the cart Context. To retrieve the context's data, including items in the cart and the total, I’ll call useContext hook inside component function and pass CartContext. Declare const contextItems, it’s an object.Now I’ll render cart’s header, drinks, total, and checkout button. Let’s structure return statement for cart component. Div is a parent element which going to wrap whole cart container. Let’s give it attribute className and pass curly braces and styles cartContainer as a class and inside let’s define header with className attribute and styles.cartHeader as a class, typically, it will include the close button, title, and clear all button. Let’s implement button element with a className attribute styles.closeBtn as a class and here pass html entities times which is going to close icon and next title write h2 and title cart and next add another button with the className attribute and give it object class.cartClear, clear all as a value. Let’s start with header. Now I’ll wrap drinks, total and checkout within another div, div with className attribute styles,cartItemsContainer Here I’ll check if item existed in cart and If there are no items in the cart, it displays a message indicating that the cart is empty So it’s javascript method so I’ll pass curly braces and then contextItems object, we’re going to access the items from the cartContext object. Pass contextItems.items.length is equal to zero and use ternary operator with the parenthesis and pass paragraph inside with p and the message is going to there are no items in the cart and colan anohter parenthesis so specify unordered list ul element with className style cartItems. I’m going to use javascript expression so use curly braces, and I’ll loop over the items that we retrieve from contextItems and render each item. I’ll pass contextItems.items and call map method on it which is going to take item as an arguement and return … item.name and also import this cart Items inside the App at the top and return cart element in jsx as well. Let’s see if it’s working, It is, and here let’s add items in the cart and it’s working as well. It’s not looking good because we haven't declared any styling. We’ll in shortly. Now let’s define total section. So specify div with the className styles.total and pass span inside with the total value and another span with the 0 value. And then checkout button so add button with the className attribute and styles.checkoutBtn as a class and the value is going to checkout.So, we've got className with style object and I’ll use these class selectors inside module. Inside cart.module.css file I’ll write code for styling cart. Select class cartContainer, this is main container. set background color to light gray and set fix width of 430px. Select cartHeader class and write style for header. Let’s use display flex for alignment, justify-content space between algin items center, sets margin bottom 1.2rem and padding .9rem, set color. Now I’ll style close button in cart header. Select class cartCloseBtn. Sets background color of the button to transparent, removes border, By setting it to "none," there won't be any visible border on the button. Set cursor to a pointer, sets the font size of the text, font weight 800, and text color to black. Now I’ll remove spacing around title, select parent class cartHeader and h2 tag and set margin to 0. Now select class cartClear to style the clear button in the cart header. sets the background color of the element to a very light gray, rounds the corners of the element by applying a border radius of 4 pixels, adds a padding of 0.5 rem, removes any border from the element, and changes the mouse cursor to a pointer. Now let’s styles the container that holds the cart items. Select class cartItemsContainer Sets border-top-left-radius to 35px and border-top-right-radius to 35px. These properties set rounded corners only on the top-left and top-right corners of the element. Now sets the box-sizing model for the element to "content-box, sets the background color of the container to a dark gray color, adds padding of 1.5 rems, sets the text color inside the container to a light gray color sets the height of the container to 100% of the viewport height. Now select class cartItems to styles the list of cart items. It removes padding, so padding 0 and margin to 0, sets a maximum height 25rem, and overflow auto. Now select total cost class, display flexbox for alignment justify content space between, it creates space between the flex items, align items center, font size 18px, font weight bold, font style italic and margin 1rem 0. Now styles the checkout button, we’ll define background color to specific shade of purple, display block sets button to be displayed as a block-level element, width 100%, padding .9rem, border-radius 25px, border 0, box-shadow, text color white, font size .9rem, font weight bold, and letter spacing 1px.Let’s save it all and see result in the browser now it’s clean and visually appealing. I also want to add divider between total cost section and checkout button for that let’s add another div inside cart component. So div className attribute styles object cartDevider as a class. And inside module I’ll style devider line, so select class cartDevider Sets border 1px solid light gray and margin 2rem 0 to create separation. Let’s see, perfect! Instead of just rendering name of the drink, I want to render each drink with its name, price, image, quantity, and buttons. Let’s create another component within cart folder and name it CartItem js, It’ll be responsible for an individual drink in cart. Also, create another new file named ‘CartItem.module.css responsible for styling. Inside CartItem import module with style object Now declare functional component with an anonymous function and pass props as an argument because it’ll receive properties from Cart component and export it as default. Now inside Cart componet instead of p element return nested component CartItem. So let’s import CartItem at the top and return nested element CartItem, I’ll pass various props to provide information about drink. So let’s pass key with the item id, id attribute with the item.id again name property with the item.name price item.price image item.image and quantity item.quantity Now inside CartItem component return jsx li element and give it className attribute and apply class style cartItem, I’ll define classes in imported CSS module shortly. Now Within list item define div element give it className attribute and apply style cartDetails. Display image of item with img element specify src attribute and set it to props image and alt attribute set props name to provide alternative text. Now define h3 tag and value is going to props name, displays the name of the item. Define span element with className attribute and specify class style price and pass expression props.prece. Create another div element outside this div with className attribute and class style itemQuantity, to handle quantity of drink in cart. Now inside this div declare button to decrease the quantity of the item in the cart I’m using minus sign you can import icons, Declare span element it displays the current quantity of the item. To allow user to increase the quantity of the item in the cart I’ll declare another button with plus sigh, It’s going to receive props from Cart component and these buttons will be responsible for add and remove items very soon. Now, I’ll define style inside module let’s go to CartItem.module.css file. We’ve defined classes already so I’m going to just use these as class selectors. First, let’s define styles for element with class name cartItem Set background dark grayish, set text color inside cartItem to white, add border 1px solid black, add margin bottom of 1rem, padding of 0.9rem, romove default style type with none from list items, use display flex to make element flex containers, use flex property justify content space between, and set align items center. Now select element with className cartDetails and use properties display flex, and align-items center. style images within the .cartDetails container to be small, circular thumbnails with a width and height of 50 pixels and border radius 50%. I’ll wrap this title and span within another div with the className attribute and styles cartInfo, now I’ll select this class name cartInfo and apply following style, display flex, flex direction column, padding left and right sides of the element with 0 0.9rem. Select itemQuantity class name and give it background color. Now I’ll target button elements that are descendants of element with classname itemQuantity, so set background color to transparent, border to none and color white, font size 16px and font weight bold. Let’s see result. It’s looking good. In the Cart component, let’s handle actions like removing an item from the cart or clearing the entire cart. Dispatch these actions to the cartReducer. I am going to declare three function handlers inside the Cart component: one each for the Clear Cart Item, Increasing Quantity, and Decreasing Quantity. Define function called handleClearItem using arrow function syntax. Define another function called handleIncrements that takes an itemId as its argument, responsible for incrementing the quantity of a specific item in the cart. This itemId likely represents the unique identifier of the item you want to increment in the cart. const handleIncrements = (itemId) => {} Let’s declare another new function called handleDecrements and also takes an argument id, it’ll identity which drink item you want to decrement in cart. Now within handleclearItem handler function pass contextItems object and call clearItem() function on it. Here contextItems object provides access to clearItem function, which we already declared inside context provider. Now you can define onClick event on button and pass handler function inside curly braces. So now when clear all button is clicked it’s going to dispatch action to cartReducer to clear items from cart. Now I want to call increment function when plus button is clicked in cart and pass it to context api. Inside handleIncrements function, first I’m going to use find method to search for a drink item in contextItems. Let’s define a new const named item and specify contextItems.items.find() and inside pass item as an argument and looks for an item id that match provided itemId Now checks if an item with the specified itemId was found in the cart. If such an item exists, the code block inside the if statement will execute. So create a new updatedItem object and use spread operator …item to copy all properties of the found item, now set quantity property of this new item to 1, effectively incrementing the quantity to 1. In next line, call addItem function from contextItems object and pass updatedItem inside parenthesis; it’s responsible for adding updated item with quantity 1. We already implemented logic for removal or decrementation within context, so here inside handleDecrement function call removeItem function from contextItems object … and pass id as an argument. This implies that removeItem is responsible for removing items from the cart based on their id. Now for button to work I’ll pass these handler function to nested component CartItem. Pass onAdd property and pass handler function because handleIncrements function receiving an argument itemId and because we can’t pass it directly like this, we've got to pass it as an anonymous function and pass correct item.id to update cart accordingly. Just like that set another event onRemove and call anonymous function handleDecrement with item.id. In CartItem component on decreasing button pass onClick event with property onRemove and on increasing button pass onClick event with property onAdd. Let’s save it all and let’s see if it works, click plus button you see number is increasing and click minus button and qunaity of item decreasing and if it’s one item it should remove this drink from cart press button and it does remove. Great! Now I want to update price based on quantity, I want to dynamically calculate price, so let us go to the CartItem component. Inside of this functional component, I am going to add a new const named price, and because I want to display price as a string with a dollar sign, I will use template tileral use two dollar signs, one for the string and one for running javascript expression. Now pass drink price and use multply operator and it’s going to be calculated by its quantity that we are receiving from Cart component. In JSX, instead of props.price pass new created variable price. If you go to browser and check the price is updating by its quantity dynamically if I add or decreases an item. The final step is to get the subtotal and display it in the cart. In order to accomplish this inside cart component, I’ll create a new const subtotal, that’s gonna hold a value as a string. Specify template literal, and then we’ll execute the expression. Let’s retrieve the total price of all items from the cartContext object that holds information about drinks in a shopping cart, it’s a floating-point number, now apply javascript method toFixed with value 2, used to round the total to exactly two decimal places. So pass the subtotal const inside span instead of 0 save it all and you’ll see total is also updating as well. Now I want to render this cart container as modal I want to hide this cart and only let it appear when cart button is clicked. And I’ll use another react key feature which is Portal. Portal used to allow shopping cart to appear as an overlay or separate container on top of other components. So let’s go to vscode and inside layout create new component called Modal.js and create another file named Modal.module.css. I created separated video on React Portals, so you can watch it from there. Now let’s use rafce short key to create anonymous function, remove this line we don’t this anymore and at top of this functional component import Fragment which is built-in component. In JSX, you can use <Fragment> element, without actually rendering any additional HTML element. Now Import module with styles object and in next line I’ll import createPortal method from react-dom. In JSX, I’ll use curly braces because it’s Javascript method, and specify createPortal() to it. I’ll create portal node to render my cart modal. So let’s go to index.js file which is located inside public folder. Inside this file scroll to root div element and before this rood id I’ll create another DOM element div with id overlay-root and instead overlay-root you can name it as you preferred. Now let’s go back to Modal component, and here I’ll render Cart as a modal dialog inside createPortal method. createPortal() method accepts two argument jsx and DOM element where component will be rendered. I’ll use div parent element with className attribute and set it to style.cartModal which is yet to define into module. Inside this div element provide Cart component, make sure you import it. Now after comma pass Dom element using document.getElementById() and pass id overlay-root inside which we defined earlier. That’s it this is a common technique for creating modal dialog in React application. Now inside App component instead of Cart element I’ll replace it with Modal component becuase We are rendering cart inside modal. So in JSX, above header element pass Modal as nested component also import it at the top. Now let’s give it style so it should appear as modal. Inside module select cartModal class as selector. Set position to fixed, ensures that the modal is fixed in place and doesn't move as the user scrolls the page top 10vh viwport height it sets the distance of the modal from the top of the viewport right 0 positions the modal against the right edge of the viewport, z-index 30, height 100vh, max width 100%, I’ll also give it animation called slide-out duration of 500ms and use forwards keyword. Now let’s define keyframes rules or animation named slide-out and give it starting point from and ending point to. From the beginning, set transform to translateX 100%, effectively hiding it to right of viewport. At the end of animation set transform to translateX 0%, translated back to normal position. Let’s give it height to 100%, now it’s looking good and refresh it, it’s animating well. Now I want to add toggle functionality to this modal, show and hide on button clicked. But cart button is located inside Header component and Header components nested inside App so we’ll call useState hook to our root component, that also called lifting state up. So at top import useState from react library and let’s define pattern. Use const keyword and inside square brackets set variable name toggleCart and updating function setToggleCart, call useState hook and specify initial boolean value false. I’ll use toggleCart state variable for conditional rendering, inside JSX wrap curly braces around Modal specify variable toggleCart and use AND operator, save it all and let’s see cart modal disappear because initial value is false, if I set it to true cart modal is appeared. Now let’s declare arrow function with const keyword and name it toggleCartHandler for toggling visibility of cart modal, and inside this function pass setToggleCart to update state variable now pass arrow function which takes prevState as an argument and negates previous state using not logical operator. If the previous state was true, it becomes false, and if it was false, it becomes true. In other words, it toggles the state from its current value. Now I’ll pass this handler function to Header, declare onToggle event, it’s not built-in event so you can name it as you prefer and now pass handler function toggleCartHandler inside. We’ve cart button nested inside header so let’s go to Header component and here you can props keyword or directly use onToggle within curlybraces. Now on CartButton define onClick event and set it to onToggle. Go to CartButton component and there you pass props, and on the button define onClick event with props.onClick. Passing props through multiple components is called props drilling but in my If the previous state was true, it becomes false, and if it was false, it becomes true. In other words, it toggles the state from its current value. Now I’ll pass this handler function to Header, declare onToggle event, it’s not built-in event so you can name it as you prefer and now pass handler function toggleCartHandler inside. case, passing through just two components is acceptable. Now let’s go to browser and check you’ll see cart modal disappear and now click on this cart button it slides out from right. You can click multiple times to check if it’s working properly. We’ve this close button inside Cart So I also want it to work when I click on it cart should close. I’ll declare another function called closeCartHandler using const keyword to close cart modal, and inside this function call setToggleCart and set it to false, As a result, if the toggleCart state variable is true indicating that the cart modal is open, it will now be set to false, and the cart modal will be hidden. There is a close button inside Cart so on Modal, so I’m going to define onClose event and inside curly braces, pass closeCartHandler function. Now go to modal and pass props inside parenthesis, define onClose property on Cart and pass props.onClose inside. Now go to Cart component pass props here as well inside parenthesis as well and on button declare onClick built-in event and pass property props.onClose, we were passing function handler from parent which is why we were defining our own event but on button we need to use onClick event to work it properly. Now we can check if button is working. In browser, click on close button, it disappeared. It’s good but the last thing I want when this cart modal appears is to draw shadow behind this cart modal to make it stand out. Let’s go to Modal component, I’m going to declare another createPortal before cart modal method self close div with className attribute and set style.backdrop after comma document.getElementById with id overlay-root. I also want to close modal when click outside so on div pass onClick event and pass props.onClose property receiving from App component. Now let’s specify style to create translucent background. In module select class backdrop set position to fixed, top 0, left 0, width 100%, height 100%, z-index 20 typically places it above most other page content but below the modal itself, now set background color with a semi-transparent black color with rgb and set it to 0.5 These styles create a fixed-position, full-viewport backdrop with a semi-transparent black color to dim the background content when a modal is displayed. Let’s see click on button modal will now slide in and become visible on the screen and if you click on backdrop or outside of modal, it will trigger the onClose function to close the modal. So this is what I promised you that we’ll build today, Our primary motivation for developing this simple application was that we could utilize React's key features. I hope you learned how to put together and build things up. I’ll end this here, if you’ve any questions regarding this, comment below and if you enjoyed this video please like and share and follow me on instagram. I’ll see you in next one.
Info
Channel: Elpeeda
Views: 156
Rating: undefined out of 5
Keywords: react project, programming tutorial, web development, code with me, react app, functional component, important hooks, context api, coding for beginners, beginner's guide, app ui, shopping cart, react js coding practice, react usecontext tutorial, react component and props
Id: Du020Qm_4GQ
Channel Id: undefined
Length: 116min 11sec (6971 seconds)
Published: Thu Dec 21 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.