How do I get the value of useState from component A to component B

86
June 01, 2021, at 00:50 AM

I'm relatively new to JS and React as a whole, I delved into React and started making some projects with Django backend. I have a list of items in the ProductList component in react,

I have a state cart I want to access from ProductList to Cart component. the Idea is when the add to cart button is clicked, the item gets added to cart array of objects How do I get the values added to Cart component? also if there is a better way to do this a suggestion would be nice.

ProductList component

import React, { useEffect, useState } from 'react'
import axios from 'axios'
import './css/ProductList.css'
import { Link } from 'react-router-dom'
// import { CartContext } from './CartContext'

function ProductList(props) {
    const [products, setProducts] = useState([])
    const [cart, setItem] = useState([])
    
    useEffect(() => {
        axios.get('http://localhost:8000/shop')
            .then(res => {
                setProducts(res.data)
            })
            .catch(error => {
                console.log(error)
            })
    }, [])
    const addToCart = (item) =>{
        setItem([...cart, item])
    }
    // const { item } = useContext(CartContext)
    return (
        <>
            {
                products.map((product) => (
                    <div className="Box" key={product.id}>
                        {product.items.map((item) => (
                            <div key={item.id} >
                                <img src={item.attachment.attachment} alt={product.name} />
                                <h5>{item.color}</h5>
                                <button className="add" onClick={()=>{addToCart(item)}}>Add to cart</button>
                            </div>
                        ))}
                        
                        <Link to={`/products/${product.id}`}><h4>{product.name}</h4></Link>
                        <p>{product.description}</p>
                    </div>
                ))
            }
        </>
    )
}
export default ProductList

Cart component.

import React from 'react'

function Cart(props) {
    return (
        <div>
        </div>
    )
}
export default Cart
Answer 1

there are already good opinions in the comments, so i actually wrote the code simply.

child component (Cart) should avoid changing the state of parent component (ProductList). so, in the parent component, the method for adding product is passed as props. after that, the child component calls the method to add it.

the above solution is what Rajdeep Debnath said in the comments.

ProductList

export default function ProductList() {
  //...
  return (
      <div>
        {products.map((product) => {
          return (
            <Cart key={product.id} product={product} addToCart={(product) => addToCart(product)} />
          );
        })}
      </div>
  );
}

Cart

export default function Cart({ product, addToCart }) {
  return (
    <div onClick={() => addToCart(product)}>
      <div>{product.id}</div>
      <div>{product.content}</div>
    </div>
  );
}
Answer 2

Context way of solving the problem

But please be aware you use context only -> If you only want to avoid passing some props through many levels, the component composition is often a simpler solution than context.

// cart.context.js
import * as React from "react";
const CartContext = React.createContext();
function CartProvider({ children }) {
  const [cart, setCart] = React.useState([]);
  
  const contextValue = {
    cart: cart,
    addToCart: (product) => {
      setCart(c => [...c, product])
    }
    // add any functions that update the cart here like addToCart
  }
  return (
    <CartContext.Provider value={contextValue}>{children}</CartContext.Provider>
  );
}

// Below is a simple hook that gives you the `contextValue` above
function useCart() {
  const context = React.useContext(CartContext);
  if (context === undefined) {
    throw new Error("useCart must be used within a CartProvider");
  }
  return context;
}
export { CartProvider, useCart };

Then wrap your nearest parent for both Cart and ProductList with below

Assuming it is App but try to wrap the nearest parent

import { CartProvider } from '...cart.context.js';
function App() {
  return (
    <CartProvider>
      // ... App component return goes here (wrap)  
    </CartProvider>
  )
}

Now you can use the useCart in all the child components like this

import { useCart } from '...cart.context.js';
export default function ProductList() {
 const { addToCart }  = useCart();
  return (
      <div>
        {products.map((product) => {
          return (
            <Cart key={product.id} product={product} addToCart={(product) => addToCart(product)} />
          );
        })}
      </div>
  );
}
import React from 'react'
import { useCart } from '...cart.context.js';
function Cart(props) {
 const { cart }  = useCart();
    return (
        <div>
        </div>
    )
}
export default Cart
Rent Charter Buses Company
READ ALSO
Node application crashes due to mysql error &#39;PROTOCOL_PACKETS_OUT_OF_ORDER&#39;

Node application crashes due to mysql error 'PROTOCOL_PACKETS_OUT_OF_ORDER'

I am running a nodejs application (web service using express) on RHEL v8, using node v16

159
Javascript and jquery I can&#39;t read value from array index

Javascript and jquery I can't read value from array index

I have a list of numbers (ex"20,145") that returns from an ajax call and I am pushing them to a js array

97
I want to filter the clients of every agent individually. Django

I want to filter the clients of every agent individually. Django

I'm creating a view where I can show all the clients of specific agents via there PK

188
Vue.js disable blank comments

Vue.js disable blank comments

Usually, when Vuejs hides an element through v-if, a comment is left in its place

128