Open In App

Unstated Next – Lightweight State Management Library For ReactJS | Part – 3 | Shopping Cart

Last Updated : 04 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

We have implemented a shopping cart using Unstated Next In this article we are gonna learn how to handle states of more than one component in a React application using Unstated Next.

Prerequisites:

Steps to Create the React Application And Installing Module:

Step 1: Create a new react app.

npx create-react-app shopping-cart

Step 2: Go to its directory by using the below command.

cd shopping-cart

Step 3: Create components folder for adding new components and store folder for creating global store using Unstated Next library.

mkdir src/components src/store
or
mkdir src/components src/store

Step 4: Install a package called Unstated Next:

npm i unstated-next

Step 5: to verify everything is working or not, run the below command to run your application.

npm start

Project Structure:

The updated dependencies in package.json file will look like:

"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"unstated-next": "^1.1.0",
"web-vitals": "^2.1.4",
}

Approach:

  • Creating Multiple Store
    • In the src/store folder create 3 more stores for cart, users, and items. detailed explanation for creating store given in the previous articles refer that.
  • Creating Multiple Components
    • Next, we need to create 3 simple components for cart, users, and items inside the src/components folder and connect that to the App.js file.
  • Moving Providers to provider.js file:
    • This Step is very important because in the previous tutorial we added Provider directly into the App.js file. so every time we create a new store we need to that. this makes the App.js file very complex, to avoid this we add all providers to a single file and then import that into the App.js file.
    • For that, we need to create a provider.js file inside src/store and then add the below code.

Example: Below is the implementation of the above approach.

Javascript




import "./App.css";
import Cart from "./components/Cart";
import Item from "./components/Item";
import User from "./components/User";
import Provider from "./store/provider";
 
function App() {
    return (
        <div className="App">
            // it contains all 3 store providers
            <Provider> 
                <Cart />
                <User />
                <Item />
            </Provider>
        </div>
    );
}
 
export default App;


Javascript




//components/user.jsx
 
import React, { useState } from "react";
import useUser from "../store/user";
 
function User() {
    // Extracting field and methods
    const { users, addUser } = useUser.useContainer();
    // To capture user input
    const [localUser, setLocalUser] = useState("");
 
    return (
        <div
            style={{
                padding: "2vw",
                display: "flex",
                justifyContent: "left",
                width: "40vw",
                margin: "auto",
            }}
        >
            <div
                style={{
                    marginRight: "10px",
                    // Display items horizontally
                    display: "flex",
                }}
            >
                {users.length > 0 &&
                    // Mapping through users array
                    users.map((user) => ( 
                        <p key={user} style={{ marginRight: 12 }}>
                            {user}
                        </p>
 
                    ))}
            </div>
            <input
                type={"text"}
                value={localUser}
                // Updating user input
                onChange={(e) => setLocalUser(e.target.value)}
                placeholder="user name"
            ></input>
            // Adding new users
            <button onClick={() => addUser(localUser)}>Add</button>
        </div>
    );
}
 
export default User;


Javascript




//components/Item.jsx
 
import React, { useState } from "react";
import useItem from "../store/item";
 
function Item() {
    const { items, addItem } = useItem.useContainer();
    const [localItem, setLocalItem] = useState("");
    return (
        <div
            style={{
                padding: "2vw",
                display: "flex",
                justifyContent: "left",
                width: "40vw",
                margin: "auto",
            }}
        >
            <div
                style={{
                    marginRight: "10px",
                    display: "flex",
                }}
            >
                {items.length > 0 &&
                    items.map((item) => (
                        <p key={item} style={{ marginRight: 12 }}>
                            {item}
                        </p>
 
                    ))}
            </div>
            <input
                type={"text"}
                value={localItem}
                onChange={(e) => setLocalItem(e.target.value)}
                placeholder="item name"
            ></input>
            <button onClick={() => addItem(localItem)}>
                Add
            </button>
        </div>
    );
}
 
export default Item;


Javascript




store/provider.js
 
import React from "react";
 
import useUser from "./user";
import useCart from "./cart";
import useItem from "./item";
 
// "props" will contain Child components
// it named as "children"
const Provider = (props) => {
    return (
        <useCart.Provider> // for cart
            <useItem.Provider> // for Item
                // for user
                <useUser.Provider>
                    {props.children}
                </useUser.Provider>
            </useItem.Provider>
        </useCart.Provider>
    );
};
 
export default Provider;


Javascript




//cart.jsx
 
import React, { useState } from "react";
import "./cart.css";
import useCart from "../store/cart";
 
function Cart() {
    let { items, addItem, deleteItem } = useCart.useContainer();
    const [localItem, setLocalItem] = useState("");
    console.log(localItem, items);
    return (
        <div>
            <h1 className="title">Cart Items</h1>
            <ol className="items">
                {items.length > 0 ? (
                    items.map((item) => (
                        <div className="item-set">
                            <li className="item" key={item}>
                                {item}{" "}
                            </li>
                            <button className="deleteButton"
                            onClick={() => deleteItem(item)}>
                                Delete
                            </button>
                        </div>
                    ))
                ) : (
                    <p>Cart is Empty</p>
                )}
            </ol>
            <input
                type="text"
                id="newItem"
                placeholder="Item name"
                value={localItem}
                onChange={(e) => setLocalItem(e.target.value)}
            />
            <input
                type="button"
                id="submitButton"
                value="Add"
                onClick={() => {
                    addItem(localItem);
                    setLocalItem("");
                }}
            />
        </div>
    );
}
 
export default Cart;


Javascript




import { useState } from "react";
import { createContainer } from "unstated-next";
 
function useCart(initialState = []) {
    let [items, setItems] = useState(initialState);
    let addItem = (_item) => {
        setItems([...items, _item]);
    };
    let deleteItem = (_item) => {
        let newItem = items.filter((item) => item !== _item);
        setItems(newItem);
    };
    return { items, addItem, deleteItem };
}
 
export default createContainer(useCart);


CSS




/* Cart.css*/
 
.title {
    font-family: Verdana, Geneva, Tahoma, sans-serif;
    font-size: 3rem;
    background-color: rgb(172, 172, 172);
    margin: 10vh 30vw;
    padding: 10px 22px;
    width: 40vw;
    border-radius: 5px;
}
.items {
    padding: 22px;
    width: 40vw;
    border-radius: 5px;
    margin: 10vh 30vw;
    margin-top: -9vh;
    background-color: rgb(221, 221, 171);
    font-size: 1.5rem;
    list-style-type: none;
}
.item-set {
    display: flex;
    justify-content: center;
    align-items: center;
}
.item {
    width: 10vw;
    padding: 1vw;
}
.deleteButton {
    width: 10vw;
    height: 8vh;
    font-size: 1.2rem;
    border-radius: 5px;
    border: none;
    background-color: rgb(226, 148, 148);
}
.deleteButton:hover {
    background-color: rgb(211, 101, 101);
    color: rgb(255, 253, 253);
}
#newItem {
    padding: 2vh 8vw;
    outline: none;
    border: none;
    border-bottom: 2px solid rgb(172, 170, 170);
}
#submitButton {
    padding: 10px 40px;
    font-size: 1.2rem;
    border-radius: 5px;
    border: none;
    background-color: rgb(100, 214, 167);
    margin-left: 1vw;
}
#submitButton:active {
    background-color: rgb(43, 129, 93);
    color: wheat;
}


Step to Run Application: Run the application using the following command from the root directory of the project.

npm start

Output:



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads