DEV Community

Cover image for Project 66 of 100 - Lil' Apple Shopping Site with React Router, Context API, Hooks
James Hubert
James Hubert

Posted on

Project 66 of 100 - Lil' Apple Shopping Site with React Router, Context API, Hooks

Hey! I'm on a mission to make 100 React.js projects ending May 31st. Please follow my dev.to profile or my twitter for updates and feel free to reach out if you have questions. Thanks for your support!

Link to today's deployed app: Link
Link to the repo: github

So yesterday my project (link here) took me all day to complete- about 8 hours. This is pretty unacceptable but just let it be known I actually never totally understood how React Router worked before, and I have been learning hooks for sort of the first time, and I didn't even know Context well enough to use it in the application despite having successfully used it with the useContext() hook just days before on a simple theme toggling site.

For today's project I wanted to make up for my error yesterday and really use Context with the useContext hook, and why not also incorporate the React Router and React Hooks stuff I've been learning.

People like code so I'll just show you my Cart context which was pretty handy. It's probably not the kind of thing you'd use on a live site, but it worked well as an exercise with useContext().

import React, {useState} from 'react'
const CartContext = React.createContext();

function CartContextProvider(props) {
  const [cart,setCart] = useState([])

  function addToCart(productId) {
    setCart(prevCart => [...prevCart,productId])
    setTimeout(() => {
      console.log(`Product with ID ${productId} was added to the cart and the cart now contains products # ${cart.join(", ")}`)
    }, 1000);
  }

  return (
    <CartContext.Provider value={{cart,addToCart}}>
      {props.children}
    </CartContext.Provider>
  )
}

export {CartContextProvider,CartContext}
Enter fullscreen mode Exit fullscreen mode

We use that Context file to share the Provider with the application as a whole in index.js. I then consume the context to share what items were in the cart with various components including the product detail pages (where we tell users if the item is already in the cart), like so:

      {cart.includes(currentProduct.productId) && 
        <p className='productDetail__cartWarning'>This item is in your cart!</p>
      }
Enter fullscreen mode Exit fullscreen mode

As you can see we do a little check on the cart state variable shared with the component via Context and if the current product is in the array, we show a little warning to the user that this product is already in their cart. It works if it's already added and if they just added it.

I then heavily relied on Context for the Cart page where we create a little state variable to store text data on the items in the cart and display a bill, and the cart total.

...

function Cart() {
  const [total,setTotal] = useState(0)
  const [itemizedBill,setItemizedBill] = useState([])
  const {cart} = useContext(CartContext)
  const history = useHistory()

  function getProduct(id) {
    return productsData.find(obj => obj.productId === id)
  }

...

  useEffect(() => {
    cart.forEach(id => {
      const currentProduct = getProduct(id)
      setTotal(prevTotal => prevTotal + currentProduct.price)
      const currentProductObj = {
        "title": currentProduct.title,
        "price": currentProduct.price
      }
      setItemizedBill(prevBill => [...prevBill, currentProductObj])
    })
  }, [cart])

  const cartList = itemizedBill.map((obj,idx) => {
    return (
      <li key={idx}>
        <strong>{obj.title}</strong> - ${obj.price}
        <button onClick={handleRemoveFromCart}>Remove</button>
      </li>
    )
  })

  return (
    <div className='page__innerContainer'>
      <button onClick={() => history.push('/')}>Back to Shopping</button>
      <h1>Shopping Cart</h1>
      <ul>
        {cartList}
      </ul>
      <h3>Total: ${total}</h3>
    </div>
  )
}

export default Cart
Enter fullscreen mode Exit fullscreen mode

If you like projects like this and want to stay up to date with more, check out my Twitter @jwhubert91, I follow back! See you tomorrow for another project.

Top comments (0)