简体   繁体   中英

How can I update my parent state from child component?

I'm currently developing a React app (ES6) whereby a number of food items will be listed.

Each time a product has been clicked, the individual product count (child state) should increase by 1 each time, which currently works.

However, the total calorie count (parent state) should also increase using the data from the parent foods state.

Example: A user clicks on the Brussel Sprouts item. The FoodItem count will increase by +1 on each click, however I also require the overall calorie count in the App class (this.state.calorieCount) to increment, by 28.1 on each click in this instance.

I'm fairly new to react so any help on this would be much appreciated.

// FoodCards.js

const FoodCards = [
    {
        id: 0,
        name: 'Brussel Sprouts',
        quantity: '1/2 cup',
        calories: 28.1,
        betacarotene: 0.363,
        bilberry_fruit: 0,
        curcumin: 0,
        grapeseed: 0,
        green_tea: 0, 
        lutein: 1,
        lycopene: 0,
        vitamin_a: 0.03,
        vitamin_d: 0
    },
    ...
];
export default FoodCards

// App.js

import React from 'react';
import './tailwind.output.css';
import './App.scss';
import FoodCards from './data/foods';

class App extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      foods: FoodCards,
      calorieCount: 0,
      vitaminACount: 0,
      vitaminDCount: 0,
    };
    this.increment = this.increment.bind(this);
  }

  increment(calories, vitaminA, vitaminD) {
    this.setState({
      calorieCount: Math.round(this.state.calorieCount + calories),
      vitaminACount: Math.round((this.state.vitaminACount + vitaminA) * 100) / 100,
      vitaminDCount: Math.round((this.state.vitaminDCount + vitaminD) * 100) / 100
    });
  };

  reset() {
    this.setState({
      calorieCount: 0,
      vitaminACount: 0,
      vitaminDCount: 0,
    });
  };

  render() {

    return (
      <div className="App">
        
        <header className="flex flex-wrap">
          <div className="calories-total">
            <span>Calories</span>
            <span className="num">{this.state.calorieCount}</span>
          </div>
  
          <div className="vitamin-a-total">
            <span>Vitamin A</span>
            <span className="num">{this.state.vitaminACount}</span>
          </div>
  
          <div className="vitamin-d-total">
            <span>Vitamin D</span>
            <span className="num">{this.state.vitaminDCount}</span>
          </div>
  
          <div className="export-btn flex items-center justify-center">
            Export Full Report
          </div>
  
        </header>
  
        <main className="products-grid flex flex-wrap">
  
        {this.state.foods.map((item, i) => {
          return <FoodItem key={item.id} name={ item.name } calories={item.calories} />
        })}
  
        </main>

        <footer>
          <div className="reset" onClick={() => this.reset()}>Reset</div>
        </footer>
  
      </div>
    );
  }
}

export default App;

class FoodItem extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      clickCount: 0
    };
  }

  handleClickIncrement() {
    this.setState({
      clickCount: this.state.clickCount + 1
    });
  };

  render() {
    return (
      <div className="product" onClick={() => this.handleClickIncrement()}>
        <p>{this.props.name} - {this.state.clickCount}</p>
        <p>Calories: {this.props.calories}</p>
      </div>
    );
  }
}

Your FoodItem needs a function with which it can notify the parent. So in App you can give it something like this:

  <FoodItem
    updateParent={this.updateFromItem.bind(this)}
    // other props
  />

Also in the Parent

  updateFromItem(calories) {
    this.increment(calories, 0, 0);
  }

The updateFromItem function sits within the parent component and via bind(this) it is scoped to it, but you propagate the change from the child (FoodItem) and call it from there:

  handleClickIncrement() {
    this.props.updateParent(this.props.calories);
    // ...
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM