简体   繁体   English

每当子组件呈现时,如何更改父组件的状态值?

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

I am learning React and I'm trying to figure out how can I change the state of a parent component whenever a child component renders.我正在学习 React,我试图弄清楚如何在子组件呈现时更改父组件的状态。

Here is what I have done so far:这是我到目前为止所做的:

  1. I passed the parent's state & setState and used useEffect, that produced unlimited renders.我通过了父级的 state 和 setState 并使用了 useEffect,它产生了无限的渲染。
  2. I tried calling the function before render, that produced unlimited renders again.我尝试在渲染之前调用该函数,这再次产生了无限渲染。
  3. I tried using forEach, didn't work.我尝试使用 forEach,没有用。

Here's a codesandbox https://codesandbox.io/s/modest-almeida-f9spo?file=/src/App.js这是一个代码和框https://codesandbox.io/s/modest-almeida-f9spo?file=/src/App.js

and here's the code这是代码

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 does not really want you to have a bidirectional data flow. React 并不真的希望您拥有双向数据流。 However it is possible using the new Two-way Binding Helpers: https://reactjs.org/docs/two-way-binding-helpers.html但是,可以使用新的双向绑定助手: https : //reactjs.org/docs/two-way-binding-helpers.html

Keep in mind though, that a change in the parent caused by the child can make the parent rerender, which in turn can make a change in the child and result in an infinite loop.但是请记住,由子项引起的父项的更改可以使父项重新渲染,这反过来又可以使子项发生更改并导致无限循环。

You can also checkout libraries like Redux ( https://redux.js.org/ ), to have a global storage every component can access and subscribe to events.您还可以查看 Redux ( https://redux.js.org/ ) 等库,以获得每个组件都可以访问和订阅事件的全局存储。

You should look into using React Redux to manage this type of behaviour.您应该考虑使用 React Redux 来管理此类行为。

However, you can pass a callback function from the Parent component to the Child component.但是,您可以将回调函数从父组件传递给子组件。

Example:例子:

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 }/>
    );
  }
}

In the parent component you declare a function, you change the parent state within this function whenever it is triggered.在你声明一个函数的父组件中,只要它被触发,你就会在这个函数中改变父状态。

You then pass the function down to the child component as a prop.然后将该函数作为 prop 传递给子组件。

When the child component mounts, you trigger the function passed as a prop.当子组件挂载时,您会触发作为 prop 传递的函数。

This triggers the function in the parent component and changes it's state, causing a re-render.这会触发父组件中的函数并更改其状态,从而导致重新渲染。

This should never result in an infinite loop because componentDidMount() in the child component only gets triggered on the initial mount of a component.这永远不会导致无限循环,因为子组件中的 componentDidMount() 仅在组件的初始安装时触发。


This technique should be used with caution because there are better ways to manage things, like using state management middleware such as Redux.应谨慎使用此技术,因为有更好的方法来管理事物,例如使用 Redux 等状态管理中间件。

It is probably acceptable if it is merely just to notify the parent that the child has rendered but it is common practice and encouraged for the data to flow from parents to children.如果仅通知父级已呈现子级,这可能是可以接受的,但这是普遍的做法,并鼓励数据从父级流向子级。

Any data in a child component that is needed in a parent component is usually moved up to the parent.父组件中需要的子组件中的任何数据通常都会向上移动到父组件。 The process of moving state up is called "Lifting State Up".向上移动状态的过程称为“提升状态”。

Calculate totalPrice and Discount in parent component在父组件中计算 totalPrice 和 Discount

Try below code:试试下面的代码:

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