Michal Vrabec
Michal Vrabec

Reputation: 39

React Add Item with spread operator

my question is about React add and edit items.I want to add object in array (object which contain amount, amountUnit, name in array) console.log is OK but object wasn´t added. On my Form a cannot show result of this function. I want to add new object of list of ingredietns from API. I dont know if i have bad props or states

import React, { Component } from "react";
import {
  FormGroup,
  FormControl,
  ControlLabel,
  InputGroup
} from "react-bootstrap";
export default class AddIngredient extends Component {
  constructor(props) {
    super(props);
    this.state = {
      ingredients: [],
      amount: " ",
      amountUnit: " ",
      name: " "
    };
  }

  onChangeAmount = e => {
    this.setState({ amount: e.target.value });
    console.log("amount was changed");
  };

  onChangeAmountUnit = e => {
    this.setState({ amountUnit: e.target.value });
    console.log("amount unit was changed");
  };
  onChangeName = e => {
    this.setState({ name: e.target.value });
    console.log("name was changed");
  };

  onClickAddIngredient = e => {
    const { amount, amountUnit, name } = this.state;
    const newIngredient = { amount, amountUnit, name };
    this.setState({ ingredients: [...this.state.ingredients, newIngredient] });

    console.log("was added");
  };

  render() {
    const { amount, amountUnit, name } = this.props;
    return (
      <React.Fragment>
        <FormGroup>
          <ControlLabel>Přidat ingredienci</ControlLabel>
          <InputGroup className="frow">
            <FormControl
              type="number"
              placeholder="Množství"
              min="0"
              value={amount}
              onChange={this.onChangeAmount}
            />
            <FormControl
              type="text"
              placeholder="Jednotka"
              value={amountUnit}
              onChange={this.onChangeAmountUnit}
            />
          </InputGroup>
          <InputGroup>
            <FormControl
              type="text"
              placeholder="Název"
              value={name}
              onChange={this.onChangeName}
            />
            <InputGroup.Addon>
              <button onClick={this.onClickAddIngredient} className={"addon"}>
                Přidat
              </button>
            </InputGroup.Addon>
          </InputGroup>
        </FormGroup>
      </React.Fragment>
    );
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

import React, { Component } from "react";

import IngredientItems from "./IngredientItems";
import AddIngredient from "./AddIngredient";
import Directions from "./Directions";
import { FormGroup, Button, ButtonGroup, Grid } from "react-bootstrap";
import BasicInfo from "./BasicInfo";
export default class RecipeForm extends Component {
  constructor(props) {
    super(props);
    this.state = {
      title: props.title || "",
      servingCount: props.servingCount,
      preparationTime: props.preparationTime,
      sideDish: props.sideDish,
      directions: props.directions,
      ingredients: props.ingredients
    };
  }

  onChange = (key, value) => {
    this.setState({ [key]: value });
  };

  render() {
    const { onCancel } = this.props;
    const {
      ingredients,
      title,
      servingCount,
      sideDish,
      preparationTime,
      directions
    } = this.state;

    return (
      <Grid>
        <ButtonGroup
          className="pull-right"
          size="lg"
          aria-label="Basic example"
        >
          <Button onClick={this.onSave} bsStyle="success">
            Uložit
          </Button>
          <Button onClick={onCancel} bsStyle="default">
            Zrušit
          </Button>
        </ButtonGroup>
        <BasicInfo
          title={title}
          preparationTime={preparationTime}
          servingCount={servingCount}
          sideDish={sideDish}
          onChange={this.onChange}
        />
        <IngredientItems ingredients={ingredients} />
        <Directions directions={directions} onChange={this.onChange} />
        <AddIngredient onChange={this.onChange} />
        <FormGroup />
      </Grid>
    );
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Upvotes: 2

Views: 985

Answers (1)

Austin Greco
Austin Greco

Reputation: 33544

You have local state ingredients in your AddIngredient component, but it is never actually rendered.

It looks like what you want to do is pass a handler to that component, which updates the ingredient array in the parent component.

AddIngredient.js

onClickAddIngredient = e => {
  const { amount, amountUnit, name } = this.state;
  const newIngredient = { amount, amountUnit, name };

  // call handler from parent and update there
  this.props.onAdd(newIngredient);

  console.log("was added");
};

RecipeForm.js

onAddIngredient = (newIngredient) => {
  this.setState({ ingredients: [...this.state.ingredients, newIngredient] });
};

Also it looks like you don't need to pass the onChange down to this component, since the input fields are just being held in it's local state. So you can just render it like this with the new handler added:

<AddIngredient onAdd={this.onAddIngredient} />

Then you can remove the local state ingredients in the subcomponent since it's not being used.

Upvotes: 1

Related Questions