Search code examples
reactjsvariablescomponentsjsxreact-props

How do I pass a variable to another component and display it in another file


I am trying to create a cart page. I have a product file that fetches products from fakestoreapi, maps through them and displays it. There is also a button that onClick passes product(a single product object retrieved from the fetched data) to another component (CarItems) and creates divs containing cart items.

My problem is I seem to only be able to display it on the product file page rather than the cart file that I want.

I've tried separating the CartItems component to another file but that seems to stop any variable from passing to it. Tried using propTypes from on tutorial but that also didn't help. Any solution would only allow me to display the items of the cart in my product page file.

Product.jsx

import { useState } from 'react'
import { useEffect } from 'react'
import './Products.css'
import NavBar from './NavBar.jsx'

function CartItems({ products }) {
    const [quantity, setQuantity] = useState(0);

    function add() {
        setQuantity(quantity + 1);
    }

    function subtract() {
        if (quantity > 0) {
            setQuantity(quantity - 1);
        }
    }

    if (products && products.length === 0) {
        console.log("Empty Cart")
        return (
            <>
                <h2>Cart is Empty</h2>
            </>
        )
        
    } else {
        console.log("Car has items")
        return (
            <div id="cartItemList">
                {products && products.map(product => (
                    <div className="cartItem" key={product.id}>
                            <img src={product.image} alt={product.title} />
                            <p>{product.title}</p>
                            <p>{product.description}</p>
                            <p>${product.price}</p>
                            <div>
                                <button onClick={subtract}>-</button>
                                <p>{quantity}</p>
                                <button onClick={add}>+</button>
                            </div>
                        </div>
                ))}
            </div>
        )
    }

}

function Products() {
    const [data, setData] = useState([]);
    const [cartProducts, setCartProducts] = useState([]);

    useEffect(() => {
        fetch('https://fakestoreapi.com/products?limit=4')
            .then(response => response.json())
            .then((data) => setData(data))
            .catch((error) => console.error(error));
    }, []);

    function addToCart(product) {
        setCartProducts(prevCart => [...prevCart, product]);
    }
    
    return (
        <>
            <NavBar />
            <div id="productsContainer">
                {data.map(product => (
                    <div className="productBoxes" key={product.id}>
                        <img className="productImg" src={product.image} alt={product.title} />
                        <h1>{product.title}</h1>
                        <p>{product.description}</p>
                        <p>${product.price}</p>
                        <button onClick={() => addToCart(product)} className="productCheck" id="productButton">Add to Cart</button>
                    </div>
                ))}
                <CartItems products={cartProducts} />
            </div>
        </>
    );
}

export { Products, CartItems };



Cart.jsx

// import { useState } from 'react'
import './Cart.css'
import NavBar from './NavBar.jsx'
import { CartItems } from './Products.jsx'

function Cart() {
    return (
        <>
            <NavBar />
            <CartItems />
        </>
    );
}


export default Cart;

App.jsx

import NavBar from './NavBar.jsx'
import './App.css'

function App() {  
  return (
    <>
        <NavBar />
        <div id="hero">
          <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Sapiente, ullam quaerat. Dolores labore aspernatur eos, molestiae hic laboriosam, magni nostrum vel aut mollitia voluptatum ducimus nesciunt minima, voluptas ea explicabo.</p>
          <a href="products"><button>Products</button></a>
        </div>
        <footer>
          <p>Made by Christian A. Valeri</p>
        </footer>
    </>
  )
}

export default App;

Main.jsx

import React from 'react'
import ReactDOM from 'react-dom/client'
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import App from './App.jsx'
import Cart from './Cart.jsx'
import {CartItems, Products} from './Products.jsx'

const router = createBrowserRouter([
  {
    path: "/",
    element: <App />,
  },
  {
    path: "/App",
    element: <App />,
  },
  {
    path: "/products",
    element: <Products />,
  },
  {
    path: "/cart",
    element: <Cart />,
  },
]);

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>
);

Solution

  • Right now, only 2 ways come to my mind for achieving what you want. The first is using the useParams hook provided by react-router-dom, and the second would be to use any state management library like redux or React's in-built Context API with useState or useReducer.

    I opted in for Context API + useState hook because it'd be easier for you to understand and it is very scalable. Here's the solution:

    main.jsx

    import React from "react";
    import ReactDOM from "react-dom/client";
    import { createBrowserRouter, RouterProvider } from "react-router-dom";
    import App from "./App";
    import Cart from "./components/Cart";
    import Products from "./components/Products";
    import ProductContextProvider from "./context/ProductContext";
    
    const router = createBrowserRouter([
      {
        path: "/",
        element: <App />,
      },
      {
        path: "/App",
        element: <App />,
      },
      {
        path: "/products",
        element: <Products />,
      },
      {
        path: "/cart",
        element: <Cart />,
      },
    ]);
    
    ReactDOM.createRoot(document.getElementById("root")).render(
      <React.StrictMode>
        <ProductContextProvider>
          <RouterProvider router={router} />
        </ProductContextProvider>
      </React.StrictMode>
    );
    

    App.jsx

    import { Link } from "react-router-dom";
    
    function App() {
      return (
        <>
          <div id="hero">
            <p>
              Lorem ipsum dolor sit amet consectetur adipisicing elit. Sapiente,
              ullam quaerat. Dolores labore aspernatur eos, molestiae hic
              laboriosam, magni nostrum vel aut mollitia voluptatum ducimus nesciunt
              minima, voluptas ea explicabo.
            </p>
            <Link to="/products">
              <button>Products</button>
            </Link>
          </div>
          <footer>
            <p>Made by Christian A. Valeri</p>
          </footer>
        </>
      );
    }
    
    export default App;
    

    The following files are located in a folder named "components":

    Cart.jsx

    import { useProductContext } from "../context/ProductContext";
    import CartItems from "./CartItems";
    
    function Cart() {
      const { cartProducts } = useProductContext();
      return <CartItems products={cartProducts} />;
    }
    
    export default Cart;
    

    CartItems.jsx

    import { useState } from "react";
    
    function CartItems({ products }) {
      const [quantity, setQuantity] = useState(0);
    
      function add() {
        setQuantity(quantity + 1);
      }
    
      function subtract() {
        if (quantity > 0) {
          setQuantity(quantity - 1);
        }
      }
    
      if (products && products.length === 0) {
        console.log("Empty Cart");
        return (
          <>
            <h2>Cart is Empty</h2>
          </>
        );
      } else {
        console.log("Cart has items");
        return (
          <div id="cartItemList">
            {products &&
              products.map((product) => (
                <div className="cartItem" key={product.id}>
                  <img src={product.image} alt={product.title} />
                  <p>{product.title}</p>
                  <p>{product.description}</p>
                  <p>${product.price}</p>
                  <div>
                    <button onClick={subtract}>-</button>
                    <p>{quantity}</p>
                    <button onClick={add}>+</button>
                  </div>
                </div>
              ))}
          </div>
        );
      }
    }
    
    export default CartItems;
    

    Products.jsx

    import { useState } from "react";
    import { useEffect } from "react";
    import { useProductContext } from "../context/ProductContext";
    import { Link } from "react-router-dom";
    
    function Products() {
      const [data, setData] = useState([]);
    
      const { addToCart } = useProductContext();
    
      useEffect(() => {
        fetch("https://fakestoreapi.com/products?limit=4")
          .then((response) => response.json())
          .then((data) => setData(data))
          .catch((error) => console.error(error));
      }, []);
    
      return (
        <div id="productsContainer">
          {data.map((product) => (
            <div className="productBoxes" key={product.id}>
              <img className="productImg" src={product.image} alt={product.title} />
              <h1>{product.title}</h1>
              <p>{product.description}</p>
              <p>${product.price}</p>
              <button
                onClick={() => {
                  addToCart(product);
                  alert("Product added to cart");
                }}
                className="productCheck"
                id="productButton"
              >
                Add to Cart
              </button>
            </div>
          ))}
          <br />
          <br />
          <br />
          <br />
          <br />
          <Link to="/cart">
            <button>Checkout</button>
          </Link>
        </div>
      );
    }
    
    export default Products;
    

    This file below is stored in a folder called "context":

    ProductContext.jsx

    import { createContext, useContext, useState } from "react";
    
    const ProductContext = createContext([]);
    
    function ProductContextProvider({ children }) {
      const [cartProducts, setCartProducts] = useState([]);
    
      const addToCart = (product) => {
        setCartProducts((prevCart) => [...prevCart, product]);
      };
      return (
        <ProductContext.Provider value={{ cartProducts, addToCart }}>
          {children}
        </ProductContext.Provider>
      );
    }
    export default ProductContextProvider;
    
    function useProductContext() {
      return useContext(ProductContext);
    }
    export { useProductContext };
    

    Try this and get back to me if you have any further questions

    #react #context #react-hooks #javascript