簡體   English   中英

每當子組件呈現時,如何更改父組件的狀態值?

[英]How do I change the values of a state of a parent component whenever a child component renders?

我正在學習 React,我試圖弄清楚如何在子組件呈現時更改父組件的狀態。

這是我到目前為止所做的:

  1. 我通過了父級的 state 和 setState 並使用了 useEffect,它產生了無限的渲染。
  2. 我嘗試在渲染之前調用該函數,這再次產生了無限渲染。
  3. 我嘗試使用 forEach,沒有用。

這是一個代碼和框https://codesandbox.io/s/modest-almeida-f9spo?file=/src/App.js

這是代碼

import React, { useState, useEffect } from "react";
import "./styles.css";
import data from "./data";

export default function App() {
  const [total, setTotal] = useState({
    price: 0,
    discount: 0
  });

  function calcTotal(prop, value) {
    const newTotal = { ...total };
    newTotal[prop] += value;
    setTotal(newTotal);
  }

  return (
    <div className="App">
      <table>
        <thead>
          <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Price</th>
          </tr>
        </thead>
        <tbody>
          {data.map((item) => (
            <Item
              key={item.id}
              data={item}
              calcTotal={calcTotal}
              total={total}
            />
          ))}
        </tbody>
        <Total total={total} />
      </table>
    </div>
  );
}

function Item(props) {
  const item = props.data;
  const calcTotal = props.calcTotal;

  useEffect(() => {
    calcTotal("price", item.price);
    calcTotal("discount", item.discount);
  }, []);

  return (
    <tr>
      <td>{item.id}</td>
      <td>{item.name}</td>
      <td>{item.price}</td>
    </tr>
  );
}

function Total(props) {
  const total = props.total;
  return (
    <tfoot>
      <tr>
        <th colSpan="2">Total Price: </th>
        <td>{total.price}</td>
      </tr>
      <tr>
        <th colSpan="2">Total Discount: </th>
        <td>{total.discount} </td>
      </tr>
    </tfoot>
  );
}

React 並不真的希望您擁有雙向數據流。 但是,可以使用新的雙向綁定助手: https : //reactjs.org/docs/two-way-binding-helpers.html

但是請記住,由子項引起的父項的更改可以使父項重新渲染,這反過來又可以使子項發生更改並導致無限循環。

您還可以查看 Redux ( https://redux.js.org/ ) 等庫,以獲得每個組件都可以訪問和訂閱事件的全局存儲。

您應該考慮使用 React Redux 來管理此類行為。

但是,您可以將回調函數從父組件傳遞給子組件。

例子:

class ChildComponent extends React.Component {

  constructor(props)
  {
    super(props);
  }

  componentDidMount()
  {
    props.onChildRendered();
  }

  render() {
    return (
      
    );
  }
}

class ParentComponent extends React.Component {

  constructor(props)
  {
    super(props);

    this.state = {
      childRendered = false;
    }
  }

  onChildRendered = () => {
    this.setState({
      childRendered: true
    });
  }

  render() {
    return (
      <ChildComponent onChildRendered={ this.onChildRendered }/>
    );
  }
}

在你聲明一個函數的父組件中,只要它被觸發,你就會在這個函數中改變父狀態。

然后將該函數作為 prop 傳遞給子組件。

當子組件掛載時,您會觸發作為 prop 傳遞的函數。

這會觸發父組件中的函數並更改其狀態,從而導致重新渲染。

這永遠不會導致無限循環,因為子組件中的 componentDidMount() 僅在組件的初始安裝時觸發。


應謹慎使用此技術,因為有更好的方法來管理事物,例如使用 Redux 等狀態管理中間件。

如果僅通知父級已呈現子級,這可能是可以接受的,但這是普遍的做法,並鼓勵數據從父級流向子級。

父組件中需要的子組件中的任何數據通常都會向上移動到父組件。 向上移動狀態的過程稱為“提升狀態”。

在父組件中計算 totalPrice 和 Discount

試試下面的代碼:

import React, { useState, useEffect } from "react";
import "./styles.css";
import data from "./data";

export default function App() {
  const [total, setTotal] = useState({
    price: 0,
    discount: 0
  });

  useEffect((prop) => {
    calcTotal();
  }, []);

  function calcTotal() {
    const newTotal = { ...total };
    data.forEach((item) => {
      newTotal.price += item.price;
      newTotal.discount += item.discount;
    });
    setTotal(newTotal);
  }

  return (
    <div className="App">
      <div>{JSON.stringify(data)}</div>
      <table>
        <thead>
          <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Price</th>
          </tr>
        </thead>
        <tbody>
          {data.map((item) => (
            <Item key={item.id} data={item} total={total} />
          ))}
        </tbody>
        <Total total={total} />
      </table>
    </div>
  );
}

function Item(props) {
  const item = props.data;
  return (
    <tr>
      <td>{item.id}</td>
      <td>{item.name}</td>
      <td>{item.price}</td>
    </tr>
  );
}

function Total(props) {
  const total = props.total;
  return (
    <tfoot>
      <tr>
        <th colSpan="2">Total Price: </th>
        <td>{total.price}</td>
      </tr>
      <tr>
        <th colSpan="2">Total Discount: </th>
        <td>{total.discount} </td>
      </tr>
    </tfoot>
  );
}

暫無
暫無

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

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