如何在React中从一个组件传递变量的值到另一个组件

huangapple go评论78阅读模式
英文:

How to pass the value of a variable from one component to another in React

问题

"CartContainer.jsx" 用于计算用户添加到购物车中的产品的成本。

"PaymentContainer.jsx" 这个组件与 Stripe.js 一起使用,并具有一个 "amount" 变量。

我希望从 "CartContainer.jsx" 中获取项目的总成本,并将其分配给 "PaymentContainer.jsx" 中的 "amount" 变量。

感谢大家 如何在React中从一个组件传递变量的值到另一个组件

英文:

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 如何在React中从一个组件传递变量的值到另一个组件

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.

如何在React中从一个组件传递变量的值到另一个组件

答案1

得分: 3

在React中,你可以通过props或全局状态将数据传递给其他组件,因此一种方法是在CartContainer.jsx内部渲染PaymentContainer.jsx并传递数据。

例如:

import React, { useEffect, useState } from "react";
// 其他导入项
import PaymentContainer from "./PaymentContainer";

const CartContainer = () => {
    const [tot, setTot] = useState(0);
    // 你的先前数据

    return (
        // 你的先前内容
        <PaymentContainer totalAmount={tot} />
    )
}

export default CartContainer;

你的支付容器还需要接收props以查看:

const PaymentContainer = ({totalAmount}) => {
    console.log(totalAmount);
    // 你的先前内容
    return (
        // 你的先前内容
    )
}

参考链接:https://reactjs.org/docs/components-and-props.html

英文:

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 &quot;react&quot;;
// your other imports
import PaymentContainer from &quot;./PaymentContainer&quot;;

const CartContainer = () =&gt; {
    const [tot, setTot] = useState(0);
    // your previous data

return (
  // your previous stuff
  &lt;PaymentContainer totalAmount={tot} /&gt;
 )
}

export default CartContainer

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

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

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

答案2

得分: 2

问题

您在至少两个地方渲染了PaymentContainer组件,一次在CartContainer中,传递了一个totalAmount属性:

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

另一次在路由中,没有传递任何属性:

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

在通过CartContainer中的Link导航到的第二个位置时,total未定义。

解决方案

不清楚为什么要在两个地方不同地渲染PaymentContainer,所以我会忽略这一部分。如果您想在一个路由中渲染PaymentContainer并传递数据给它,您应该通过链接在路由状态中传递它。

tot状态实际上也是不必要的,因为它是从实际的 cartItems 状态派生出来的。在React状态中存储派生状态通常被认为是React中的反模式。您应该在每个渲染周期内计算和使用它。

请注意,在几乎所有使用 useState/useEffect 钩子组合的用例中,您实际上应该使用 useMemo 钩子来计算和缓存一个稳定的值引用。

示例:

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]);

代码示例:

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

  // 其他方法

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

  // 其他方法

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

      {user ? (
        <Link to="/payment" state={{ totalAmount }}> // &lt;-- 在状态中传递totalAmount
          <motion.button
            whileTap={{ scale: 0.8 }}
            type="button"
            class...
          >
            Check Out
          </motion.button>
        </Link>
      ) : (
        //其他代码
      )}

      ...
      <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>
  );
};
英文:

Issue

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

&lt;div&gt;
  &lt;PaymentContainer totalAmount={tot} /&gt;
&lt;/div&gt;

And once in the routes where no props are passed:

&lt;Route path=&quot;/payment&quot; element={&lt;PaymentContainer /&gt;} /&gt;

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(() =&gt; {
  return cartItems.reduce(function (accumulator, item) {
    return accumulator + item.qty * item.price;
  }, 0);
}, [cartItems]);

Code Example:

const CartContainer = () =&gt; {
  const [{ cartShow, cartItems, user }, dispatch] = useStateValue();
  const [flag, setFlag] = useState(1);

  // another methods

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

  // another methods

  return (
    &lt;motion.div initial... animate... exit... class...&quot;&gt;
      ...

      {user ? (
        &lt;Link to=&quot;/payment&quot; state={{ totalAmount }}&gt; // &lt;-- pass totalAmount in state
          &lt;motion.button
            whileTap={{ scale: 0.8 }}
            type=&quot;button&quot;
            class...
          &gt;
            Check Out
          &lt;/motion.button&gt;
        &lt;/Link&gt;
      ) : (
        //another code
      )}

      ...
      &lt;PaymentContainer totalAmount={totalAmount} /&gt;
      ...
    &lt;/motion.div&gt;
  );
};
import React from &quot;react&quot;;
import { useLocation } from &#39;react-router-dom&#39;;

const PaymentContainer = ({ totalAmount }) =&gt; {
  const { state } = useLocation();

  const containerAmount = state.totalAmount || totalAmount || 0;

  React.useEffect(() =&gt; {
    console.log(totalAmount);
  }, [totalAmount]);

  return (
    &lt;div&gt;
      &lt;h2&gt;Total: {containerAmount}&lt;/h2&gt;
    &lt;/div&gt;
  );
};

huangapple
  • 本文由 发表于 2023年3月9日 20:18:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/75684514.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定