如何从子组件更新父状态?

时间:2020-07-23 13:36:24

标签: javascript reactjs ecmascript-6

我目前正在开发一个React应用(ES6),其中将列出许多食品。

每次点击产品时,单个产品计数(子状态)应每次增加1,这目前有效。

但是,使用母食品状态的数据也应增加总卡路里计数(父状态)。

示例:用户单击“抱子甘蓝”项目。 FoodItem计数每次点击将增加+1,但是在这种情况下,我还要求App类中的总卡路里计数(this.state.calorieCount)要增加28.1。

我是新来的反应者,因此在此方面的任何帮助将不胜感激。

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

1 个答案:

答案 0 :(得分:2)

您的FoodItem需要一个可以通知父项的功能。因此,在App中,您可以输入以下内容:

Input

也是在父母中

import React, { useState, useRef, forwardRef } from "react";
import Editor, { createEditorStateWithText } from "draft-js-plugins-editor";
import createEmojiPlugin from "draft-js-emoji-plugin";
import { TextField, makeStyles } from "@material-ui/core";
import { isObject } from "lodash";
import { findDOMNode } from "react-dom";
import classNames from 'classnames';

function InputWrapper(props) {
    const { component: Component, inputRef, ...other } = props;
    const ref = useRef();

    React.useImperativeHandle(inputRef, () => ({
        focus: () => {
            findDOMNode(inputRef.current).focus();
        },
    }));

    return <Component ref={ref} {...other} />;
}

const emojiPlugin = createEmojiPlugin();
const { EmojiSuggestions, EmojiSelect } = emojiPlugin;
const plugins = [emojiPlugin];
const text = `Cool, we can have all sorts of Emojis here. ?
?☃️?? aaaand maybe a few more here ?☀️? Quite fun!`;

const useStyles = makeStyles((theme) => ({
    textField: {
        width: "100%",
        minHeight: 31,
        tabSize: 8,
        fontVariantLigatures: "none",
        boxSizing: "content-box",
        userSelect: "text",
        whiteSpace: "pre-wrap",
    },
}));

let DraftInput = (props, ref) => {
    const {
        InputProps,
        InputLabelProps,
        value,
        handleEnterKeyPress,
        onChange,
        id,
        ...other
    } = props;
    const [editorState, setEditorState] = useState(
        createEditorStateWithText(text)
    );
    const baseClasses = useStyles();

    const handleChange = (state) => {
        setEditorState(state);
        // onChange(state);
    };

    const propClass =
        isObject(InputProps) && InputProps.hasOwnProperty("className")
            ? InputProps.className
            : false;

    const classes = classNames([baseClasses, propClass, "emoji-input"]);

    return (
        <div>
                <TextField
                    inputRef={ref}
                    autoFocus={true}
                    value={value}
                    InputProps={{
                        inputComponent: InputWrapper,
                        inputProps: {
                            component: Editor,
                            onChange: handleChange,
                            editorState,
                        },
                        ...InputProps,
                    }}
                    InputLabelProps={{
                        ...InputLabelProps,
                    }}
                    {...InputProps}
                    {...other}
                />
        </div>
    );
};

DraftInput = forwardRef(DraftInput);
export default DraftInput;

<FoodItem updateParent={this.updateFromItem.bind(this)} // other props /> 函数位于父组件中,并且通过 updateFromItem(calories) { this.increment(calories, 0, 0); } 对其进行了范围调整,但是您从子项(FoodItem)传播更改并从那里调用它:

updateFromItem
相关问题