簡體   English   中英

在 React 中從多個子組件向一個父組件發送信息

[英]Send information from multiple children components to one parent component in React

我有一個父組件呈現子組件subtotalstotal

function Total({ products }) {
  const [total, setTotal] = useState(0);

  const handleChildToParent = (subtotal) => {
    setTotal(total + subtotal);
  };

  return (
    <div>
      {products.map((product) => (
        <Subtotal product={product} childToParent={handleChildToParent} />
      ))}
      <span>Total: {total}</span>
    </div>
  );
}

每個Subtotal組件都包含一個項目的價格,並根據用戶選擇的單位數量計算小計。

function Subtotal({ product, childToParent }) {
  const [units, setUnits] = useState(0);

  const handleInputChange = (value) => {
    setUnits(value);
    childToParent(value * product.price);
  };

  return (
    <div>
      <input
        type="number"
        min={1}
        onChange={(e) => handleInputChange(e.target.value)}
        value={units}
      />
      <span>units * product price: {units * product.price}</span>
    </div>
  );
}

我的目標是根據子組件的信息在父組件中進行動態總計。 例如:用戶選擇兩個價格為 100 美元的項目,三個價格為 12 美元,父組件應顯示為 236 美元,子組件應顯示第一個項目為 200 美元($100x2),第一個項目為 36 美元($12x3)第二個項目(這是我目前擁有的),如果用戶對第一個項目改變主意,而不是兩個只想要一個,總價格應該更新為 136 美元。 當我嘗試減去一個項目時,我被卡住了。 我嘗試設置項目的初始總和並將 useEffect 與 total 一起使用,但我無法找到解決方案。 任何幫助將不勝感激,我實際上不知道這是否真的可以使用組件之間的子到父通信。

這是我擁有的沙箱: https://codesandbox.io/s/reverent-elbakyan-i0hr1

這是一個經典示例,您應該將 state 從“小計”組件中“提升”到父組件中。

通常,多個組件需要反映相同的變化數據。 我們建議將共享的 state 提升到最接近的共同祖先。

在這種情況下,“幾個組件需要反映相同的變化數據”的地方是您的<Total>組件,因為正如您所說:

我的目標是根據子組件的信息在父組件中進行動態總計。

React 的核心模式之一是“數據向下流動” 換句話說,數據/狀態應該在您的應用程序中處於較高級別,並從那里“向下流動”到后代。 嘗試將數據保存在“子”組件( <Subtotal> )中並且還更新其祖先中的 state 是 React 中的反模式,應該避免,因為這意味着您在兩個或多個位置跟蹤相同的 state一次。

嘗試這樣的事情:

function Total({ products }) {
  // track "subtotals" in one place in state;
  // the total value of all subtotals can be trivially derived from this
  const [subtotals, setSubtotals] = React.useState(new Array(products.length).fill(0));

  // our onChange handler will update the index of "subtotals"
  // with the passed new value
  const onChange = (newValue, i) => {
    setSubtotals(oldSubtotals => {
      const newSubtotals = [...oldSubtotals];
      newSubtotals[i] = newValue;
      return newSubtotals;
    });
  }

  let total = 0;
  for (let i = 0; i < subtotals.length; i++) {
    total += subtotals[i] * products[i].price;
  }

  return (
    <div>
      {products.map((product, i) => (
        <Subtotal product={product} value={subtotals[i]} onChange={onChange} index={i} />
      ))}
      <span>Total: {total}</span>
    </div>
  );
}

// now <Subtotal> tracks no state, it is entirely stateless;
// it simply displays the correct information and calls its onChange as needed
function Subtotal({ product, value, onChange, index }) {
  return (
    <div>
      <input
        type="number"
        // updated min to 0, unless you really want to force
        // them to buy at least one...?
        min={0}
        onChange={(e) => onChange(e.target.value, index)}
        value={value}
      />
      <span>units * product price: {value * product.price}</span>
    </div>
  );
}

現在,總值的真實來源是<Total>並且只有<Total> state 沒有奇怪的分裂,其中一個組件試圖鏡像其他組件的 state。 <Total>確切地知道每個小計正在跟蹤的值,並且只需將該值傳遞給子組件,以及 function 以更新 state。 但是您沒有在兩個地方跟蹤 state,這是非常非常糟糕的。

更新沙盒鏈接

Total組件中為 state 使用數組怎么樣?

我盡量不改變你之前寫的代碼。

const initialState = [0, 0];

function Total({ products }) {
  const [values, setValues] = useState(initialState);
  // Below is for sum of array
  const total = values.reduce((prev, val) => prev + val);

  return (
    <div>
      {products.map((product, idx) => {
        const handleChildToParent = (value) => {
          setValues(values => {
            const newValues = [...values];
            newValues[idx] = value;
            return newValues;
          })
        }

        return (
          <Subtotal product={product} childToParent={handleChildToParent} />
        );
      })}
      <span>Total: {total}</span>
    </div>
  );
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM