I'm relatively new to React and creating a ToDoList style Recipe App. The user should be able to add new recipes to the list as well as delete or edit existing recipes.
I ran into an issue getting the ingredients to display on separate lines and asked this question on how to do that. The end result was that I added a second .map function within my container to iterate through ingredients and display each one as a new paragraph element. Here is my container, Item.js:
import React from 'react';
import Button from 'react-bootstrap/lib/Button';
const Item = (props) => (
<div>
<div className="Recipe-Item-Container" key={props.text}>
{/* Iterates through recipe item names and displays them */}
{props.items.map((item, index) => {
return (
<div className="Recipe-Item" key={index}>
<h3>{item}</h3>
// This is what I added
{/* Iterates through recipe ingredients and displays them*/}
<p className="ingredients-list">
{props.ingredients[index].map((ingredient, ingredientIndex) => {
return (
<div className="ingredient" key={ingredient}>
{ingredient}
</div>
)
})}
</p>
<div className="buttons-container">
<Button className="edit-button" onClick={() => props.edit(item, index)}>Edit</Button>
<Button className="delete-button" onClick={() => props.delete(item, index)}>Delete</Button>
</div>
</div>
);
}
)}
</div>
</div>
)
export default Item;
Now the initial recipes within my state properly display ingredients on new lines, and any recipe item the user edits also displays ingredients on a new line. Exactly what I wanted.
The issue is when the user adds a new recipe the ingredients aren't displayed on new lines the way I want. If you click the add new recipe button and add a new one the ingredients are displayed side by side and as one single paragraph element.
I have two functions that handle adding a new recipe and editing an existing recipe, onSubmit and onEditSubmit. onEditSubmit is working fine because when recipes are edited the ingredients display properly on separate lines. onSubmit is the issue. How can I change onSubmit and get it to display ingredients on new lines and as separate paragraphs? I think this is an issue with how I am setting state within onSubmit and might involve the use of the spread operator.
Here is my App.js:
import React, { Component } from 'react';
import Item from './Item';
import './App.css';
import ModalComponent from './Modal.js';
import Button from 'react-bootstrap/lib/Button';
import EditModalComponent from './EditModal.js';
import SimpleStorage from "react-simple-storage";
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
items: ["Pumpkin Pie", "Spaghetti", "Onion Pie"],
ingredients:[
["Pumpkin Puree ", "Sweetened Condensed Milk ", "Eggs ", "Pumpkin Pie Spice ", "Pie Crust "],
["Noodles ", "Tomato Sauce ", "(Optional) Meatballs "],
["Onion ", "Pie Crust "]
],
// Recipe name and ingredients
inputVal: '',
ingredientVal: '',
// Recipe name and ingredients when user is editing existing recipe
inputValEdit: '',
ingredientValEdit: '',
// Controls whether forms are displayed or hidden
showRecipeForm: false,
showRecipeEditForm: false,
// Index to select which recipe item is being edited
editingIndex: ''
};
}
// Get text user inputs for recipes
handleChange = (event) => {
this.setState({ [event.target.name]: event.target.value });
};
// When user submits recipe this adds it to the list
onSubmit = (event) => {
event.preventDefault();
this.setState({
items: [...this.state.items, this.state.inputVal],
ingredients: [...this.state.ingredients, [this.state.ingredientVal]],
showRecipeForm: false
});
}
// When user edits existing recipe this adds it to the list
onEditSubmit = (event) => {
event.preventDefault();
const {items, ingredients, inputValEdit, ingredientValEdit, editingIndex} = this.state;
// Selects proper recipe item to edit
items[editingIndex] = inputValEdit;
ingredients[editingIndex] = ingredientValEdit.split(',');
this.setState({
items: items,
ingredients: ingredients,
inputVal: '',
ingredientVal: '',
showRecipeEditForm: false
});
}
closeRecipeForm = () => {
this.setState({
showRecipeForm: false,
showRecipeEditForm: false
});
}
// Shows recipe
AddRecipe = (bool) => {
this.setState({
showRecipeForm: bool
});
}
// Is called when one of the edit recipe buttons is clicked, shows RecipeEditForm
edit = (item, index) => {
this.setState({
showRecipeEditForm: !this.state.showRecipeEditForm,
editingIndex: index
});
}
// Deletes recipe item from the list
delete = (item, index) => {
this.setState({
ingredients : this.state.ingredients.filter((_, i) => i !== index),
items: this.state.items.filter((_, i) => i !== index)
});
}
render() {
return (
<div className="container">
{/* Handles storing data in local sessions via react-simple-storage*/}
<SimpleStorage parent={this} />
<h1>Recipe List</h1>
<ModalComponent
inputVal={this.state.inputVal}
handleChange={this.handleChange}
ingredientVal={this.state.ingredientVal}
onSubmit={this.onSubmit}
addRecipe={this.addRecipe}
showRecipeForm={this.state.showRecipeForm}
closeRecipeForm={this.closeRecipeForm}
/>
<EditModalComponent
inputValEdit={this.state.inputValEdit}
handleChange={this.handleChange}
ingredientValEdit={this.state.ingredientValEdit}
onEditSubmit={this.onEditSubmit}
closeRecipeForm={this.closeRecipeForm}
addRecipe={this.addRecipe}
showRecipeEditForm={this.state.showRecipeEditForm}
/>
<Item
items={this.state.items}
ingredients={this.state.ingredients}
edit={this.edit}
delete={this.delete}
/>
<Button className="add-recipe-button" onClick={this.AddRecipe}>Add New Recipe</Button>
</div>
);
}
}
Do I need to make onSubmit more similar to onEditSubmit? If so how can I do this?
this.ingredientValvariable is, if it is astringwith the same format asingredientValEdit, you'll need to use[...this.state.ingredients, this.state.ingredientVal.split(",")]instead of[...this.state.ingredients, [this.state.ingredientVal]]- Titusingredients: [...this.state.ingredients, this.state.ingredientVal]notingredients: [...this.state.ingredients, this.state.ingredientVal.split(",")]. - Titus