skip to Main Content

I use two components:
-"CartContainer.jsx" to count the cost of products that user has added to the cart.

UPDATED:

import React, { useEffect, useState } from "react";
import { useStateValue } from "../context/StateProvider";
import { actionType } from "../context/reducer";
//another imports
import { Link } from "react-router-dom";
import PaymentContainer from "./PaymentContainer";

const CartContainer = () => {
    const [{ cartShow, cartItems, user }, dispatch] = useStateValue();
    const [flag, setFlag] = useState(1);
    const [tot, setTot] = useState(0);

    //another methods

    useEffect(() => {
        let totalPrice = cartItems.reduce(function (accumulator, item) {
            return accumulator + item.qty * item.price;
        }, 0);
        setTot(totalPrice);
        console.log(tot);
    }, [tot, flag]);

    //another methods

    return (
        <motion.div initial... animate... exit... class...">

        //something code

            {/* bottom section */}

        //something code

                    {/* cart total section code */}
                    <div class...>
                        <div class...>
                            <p class...>Sub Total</p>
                            <p class...>$ {tot}</p>
                        </div>
                        <div class...>
                            <p class...>Delivery</p>
                            <p class...>$ 2.5</p>
                        </div>

                        //another code

                        <div class...>
                            <p class...>Total</p>
                            <p class...>${tot + 2.5}</p>
                        </div>

                        {user ? (
                            <Link to={'/payment'}> *//it's link to PaymentContainer*
                                <motion.button whileTap={{ scale: 0.8 }} type="button" class...>Check Out</motion.button>
                            </Link>
                        ) : (
                            //another code
                        )}
                    </div>
                    <div>
                        <PaymentContainer totalAmount={tot} />
                    </div>
                </div>
            ) : (
        //another code
            )}
        </motion.div>
    );
};

export default CartContainer;

-"PaymentContainer.jsx" this component works with Stripe.js and has a "amount"-variable.

UPDATED:

import React from "react";

const PaymentContainer = ({totalAmount}) => {
  const containerAmount = totalAmount;
  console.log(totalAmount);
  return (
    <div>
      <h2>Total: {containerAmount}</h2>
    </div>
  );
};

export default PaymentContainer;

I want the total cost of items from "CartContainer.jsx" to be assigned to the "amount"-variable in "PaymentContainer.jsx"
Thank you all 🙂

I found a similar question in this forum and tried to apply the solution, but I couldn’t.
I tried to adapt this code in file "PaymentContainer.jsx"

  const handleInputChange = (e) => {   
  const valueFilterActive = document.getElementById("activeFilter").value;
  const valueFilterName = document.getElementById("bussFilter").value;
  // this will set `inputValues` variable to be an object with `valueFilterActive` and `valueFilterName` properties
  setInputValues({valueFilterActive, valueFilterName})
  alert(valueFilterName+valueFilterActive);   
};

UPDATED: App.js

import React, { useEffect } from "react";
import { Route, Routes } from "react-router-dom";
import { AnimatePresence } from "framer-motion";
import { CreateContainer, Header, MainContainer, PaymentContainer } from "./components";
import { useStateValue } from "./context/StateProvider";
import { getAllFoodItems } from "./utils/firebaseFunctions";
import { actionType } from "./context/reducer";


const App = () => {
    const [{foodItems}, dispatch] = useStateValue();

    const fetchData = async () => {
        await getAllFoodItems().then(data => {
            dispatch({
                type : actionType.SET_FOOD_ITEMS,
                foodItems : data,
            });
        });
    };

    useEffect(() => {
        fetchData();
    }, []);

    return (
        <AnimatePresence mode="wait">
            <div class...>
                <Header />

                <main class...>
                    <Routes>
                        <Route path="/*" element={<MainContainer />} />
                        <Route path="/createItem" element={<CreateContainer />} />

            //here PaymentContainer
                        <Route path="/payment" element={<PaymentContainer />} /> here PaymentContainer
            //here PaymentContainer

                    </Routes>
                </main>
            </div>
        </AnimatePresence>
    );
}

export default App

UPDATED:

Browser console when I add products to cart and get the amount but when I go to "Payment Container" by "Link" the value is undefined.

BrowserConsole

2

Answers


  1. in React, you can pass data to other components via props or global state, so one way would be to render the PaymentContainer.jsx inside the CartContainer.jsx and pass data to it.

    For example:

    import React, { useEffect, useState } from "react";
    // your other imports
    import PaymentContainer from "./PaymentContainer";
    
    const CartContainer = () => {
        const [tot, setTot] = useState(0);
        // your previous data
    
    return (
      // your previous stuff
      <PaymentContainer totalAmount={tot} />
     )
    }
    
    export default CartContainer
    

    Your payment Container would also need to receive the props to view

    const PaymentContainer = ({totalAmount}) => {
      console.log(totalAmount)
      // your previous stuff
      return (
        // your previous stuff
      )
    }
    

    Reference: https://reactjs.org/docs/components-and-props.html

    Login or Signup to reply.
  2. Issue

    You are rendering the PaymentContainer component in at least two places, once in CartContainer where a totalAmount prop is passed:

    <div>
      <PaymentContainer totalAmount={tot} />
    </div>
    

    And once in the routes where no props are passed:

    <Route path="/payment" element={<PaymentContainer />} />
    

    It is the second that when navigated to by the Link in CartContainer that the total is undefined.

    A Solution

    It’s not clear why you are rendering PaymentContainer in two places differently, so I’ll ignore this part. If you want to render PaymentContainer on a route and pass data to it you will pass it in route state via the link.

    The tot state is actually also unnecessary since it’s derived "state" from the actual cartItems state. It’s generally considered a React anti-pattern to store derived state in React state. You should compute and use it locally per render cycle.

    Note that in almost 100% of the use cases where you find yourself coding a useState/useEffect hook combo what you really should use is the useMemo hook to compute and memoize a stable value reference.

    Examples:

    const totalPrice = cartItems.reduce(function (accumulator, item) {
      return accumulator + item.qty * item.price;
    }, 0);
    
    const totalPrice = React.useMemo(() => {
      return cartItems.reduce(function (accumulator, item) {
        return accumulator + item.qty * item.price;
      }, 0);
    }, [cartItems]);
    

    Code Example:

    const CartContainer = () => {
      const [{ cartShow, cartItems, user }, dispatch] = useStateValue();
      const [flag, setFlag] = useState(1);
    
      // another methods
    
      const totalAmount = React.useMemo(() => {
        return cartItems.reduce(function (accumulator, item) {
          return accumulator + item.qty * item.price;
        }, 0);
      }, [cartItems]);
    
      // another methods
    
      return (
        <motion.div initial... animate... exit... class...">
          ...
    
          {user ? (
            <Link to="/payment" state={{ totalAmount }}> // <-- pass totalAmount in state
              <motion.button
                whileTap={{ scale: 0.8 }}
                type="button"
                class...
              >
                Check Out
              </motion.button>
            </Link>
          ) : (
            //another code
          )}
    
          ...
          <PaymentContainer totalAmount={totalAmount} />
          ...
        </motion.div>
      );
    };
    
    import React from "react";
    import { useLocation } from 'react-router-dom';
    
    const PaymentContainer = ({ totalAmount }) => {
      const { state } = useLocation();
    
      const containerAmount = state.totalAmount || totalAmount || 0;
    
      React.useEffect(() => {
        console.log(totalAmount);
      }, [totalAmount]);
    
      return (
        <div>
          <h2>Total: {containerAmount}</h2>
        </div>
      );
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search