2017-08-03 43 views
1

我正在開發食譜書應用程序並試圖實現編輯輸入功能。 它的工作原理是輸入配方名稱(例如Pasta),然後是配料(例如雞蛋,麪粉,鹽)。成分必須以逗號輸入,並以列表形式顯示。將數據傳遞給父母 - 食譜React

  • 麪食
  • -Egg
  • -Flour

我可以看到,它是有點工作,因爲我可以看到在輸入文本中的新條目(例如,最初是雞蛋,麪粉,鹽 - >蛋,麪粉,鹽,水),當我試圖再次編輯它。

但是,額外的成分(在上面的例子中:水)沒有出現在列表中。我必須設法重新呈現列表嗎?

更新: 我想我知道錯誤可能在哪裏。傳遞數據和設置狀態有一些問題。

<EditRecipe recipe={this.props.recipe} editRecipe={this.editRecipe.bind(this, this.props.recipe.id, recipe)}/> 

App.js

import React, { Component } from 'react'; 
// import logo from './logo.svg'; 
import './App.css'; 
import uuid from 'uuid'; 
import Modal from 'react-modal'; 
import RecipeList from './components/RecipeList/RecipeList'; 
import AddRecipe from './components/AddRecipe/AddRecipe'; 

class App extends Component { 

    constructor(props){ 
    super(props); 
    this.state = { 
     recipes:[] 
    }; 
    } 

    getRecipes(){ 
    this.setState({recipes:[ 
     { 
     id: uuid.v4(), 
     food: "pumpkin pie", 
     ingredients: ["pumpkin puree", "sweetened condensed milk", "eggs", "pumpkin pie spice", "pie crust"] 
     }, 
     { 
     id: uuid.v4(), 
     food: "spaghetti", 
     ingredients: ["noodles", "tomato sauce", "meatballs"] 
     }, 
     { 
     id: uuid.v4(), 
     food: "onion pie", 
     ingredients: ["onion", "pie crust"] 
     }, 

    ]}); 
    } 

    componentWillMount(){ 
    this.getRecipes(); 
    } 

    handleAddRecipe(recipe){ 
    let recipes = this.state.recipes; 
    recipes.push(recipe); 
    this.setState({recipes: recipes}); 
    } 

    handleDeleteRecipe(id){ 
    let recipes = this.state.recipes; 
    let index = recipes.findIndex(x => x.id === id); 
    recipes.splice(index,1); 
    this.setState({recipes: recipes}); 
    } 

    handleEditRecipe(id, recipe){ 
    let recipes = this.state.recipes; 
    let index = recipes.findIndex(x => x.id === id); 
    recipes.splice(index,1,recipe); 
    this.setState({recipes: recipes}); 
    } 

    render() { 
    return (
     <div className="App"> 
     <RecipeList recipes={this.state.recipes} onDelete={this.handleDeleteRecipe.bind(this)} onEdit={this.handleEditRecipe.bind(this)}/> 
     <AddRecipe addRecipe={this.handleAddRecipe.bind(this)}/> 
     </div> 
    ); 
    } 
} 

export default App; 

RecipeList.js

import React, { Component } from 'react'; 
import Collapsible from 'react-collapsible'; 
import RecipeItem from '../RecipeItem/RecipeItem' 
import './RecipeList.css'; 

class RecipeList extends Component{ 

deleteRecipe(id){ 
    this.props.onDelete(id); 
} 

editRecipe(id, recipe){ 
    this.props.onEdit(id, recipe); 
} 

    render(){ 

    let recipeItem; 

    if(this.props.recipes){ 
     recipeItem=this.props.recipes.map(recipe => { 
     return(
      <RecipeItem onEdit={this.editRecipe.bind(this)} onDelete={this.deleteRecipe.bind(this)} key={recipe.id} recipe={recipe} /> 
     ) 
     }); 
    } 

    return(
     <div className="recipeList box"> 
     {recipeItem} 
     </div> 
    ) 
    } 
} 

export default RecipeList; 

RecipeItem.js

import React, { Component } from 'react'; 
import Collapsible from 'react-collapsible'; 
import EditRecipe from '../EditRecipe/EditRecipe'; 

class RecipeItem extends Component{ 

    deleteRecipe(id){ 
    this.props.onDelete(id); 
    } 

    editRecipe(id, recipe){ 
    this.props.onEdit(id, recipe); 
    } 

    render(){ 

    let recipe=this.props.recipe 
    let foodName=recipe.food; 
    let ingredientItem; 

    if(recipe.ingredients){ 
     ingredientItem=recipe.ingredients.map(ingredient=>{ 
     return(
      <a className="panel-block"> 
      {ingredient} 
      </a> 
     ) 
     }) 
    } 
    return(
     <ul> 
     <li className="Recipe"> 
     <Collapsible trigger={foodName} transitionTime="200" easing="ease-in-out"> 
     <nav className="panel"> 
      <p className="panel-heading"> 
      Ingredients 
      </p> 
      {ingredientItem} 
      <div className="panel-block"> 
      <button className="button is-warning is-outlined" onClick={this.deleteRecipe.bind(this, this.props.recipe.id)}> 
       Delete 
      </button> 
      <EditRecipe recipe={this.props.recipe} editRecipe={this.editRecipe.bind(this, this.props.recipe.id, recipe)}/> 
      </div> 
      </nav> 
     </Collapsible> 
     </li> 
     </ul> 
    ); 
    } 
} 

export default RecipeItem; 

EditRecipe.js

import React, { Component } from 'react'; 
import RecipeForm from '../RecipeForm/RecipeForm'; 
// import './EditRecipe.css'; 
import Modal from 'react-modal'; 
import uuid from 'uuid'; 
// import Modal from 'boron/DropModal'; 
// import './RecipeList.css'; 

class RecipeEdit extends Component{ 

    constructor(props){ 
    super(props); 
    this.state = { 
     revisedRecipe:{ 
     id: this.props.recipe.id, 
     food: this.props.recipe.food, 
     ingredients: this.props.recipe.ingredients 
     }, 
     modalIsOpen: false, 
     speed: 100 
    }; 
    this.openModal = this.openModal.bind(this); 
    this.closeModal = this.closeModal.bind(this); 
    } 

    openModal(){ 
    this.setState({modalIsOpen: true}); 
    } 

    closeModal(){ 
    this.setState({modalIsOpen: false}); 
    } 

    handleSubmit(e){ 

    const revised = this.state.revisedRecipe; 

    this.props.editRecipe(revised); 

    e.preventDefault(); 
    } 


    handleNameChange(e){ 
    this.setState({revisedRecipe:{ 
     food: e.target.value 
    } 
    }); 
    } 

    handleIndChange(e){ 
    this.setState({revisedRecipe:{ 
     ingredients: e.target.value 
    } 
    }); 
    } 



    render(){ 
    const speed = this.state.speed; 
    let recipe=this.props.recipe; 
    let foodName=this.state.revisedRecipe.food; 
    let ingredients=recipe.ingredients; 

    return(
     <div> 
     <button className="button is-primary" onClick={this.openModal}>Edit Recipe</button> 
     <Modal 
      isOpen={this.state.modalIsOpen} 
      onAfterOpen={this.afterOpenModal} 
      onRequestClose={this.closeModal} 
      closeTimeoutMS={speed} 
      contentLabel="Example Modal" 
     > 
     <div className="field"> 
      <h2 className="title is-2">Edit Recipe</h2> 
      <form> 
      <label className="label">Recipe</label> 
      <div className="control"> 
       <input className="input" type="text" placeholder="Recipe Name" ref="recipeName" value={this.state.revisedRecipe.food} onChange={this.handleNameChange.bind(this)}/> 
      </div> 
      <div className="field"> 
      <label className="label">Ingredients</label> 
      <div className="control has-icons-left has-icons-right"> 
       <input className="input" type="text" placeholder="Enter ingredients. (if more than 1 ingredient, separate them with commas)" ref="ingredients" value={this.state.revisedRecipe.ingredients} onChange={this.handleIndChange.bind(this)}/> 
       <span className="icon is-small is-left"> 
       <i className="fa fa-flask"></i> 
       </span> 
      </div> 
      </div> 
      <div className="field is-grouped"> 
       <div className="control"> 
       <button className="button is-primary" onClick={this.closeModal}>Edit Recipe</button> 
       </div> 
       <div className="control"> 
       <button className="button" onClick={this.closeModal}>Cancel</button> 
       </div> 
      </div> 
      </form> 
     </div> 
     </Modal> 
     </div> 
    ); 
    } 
} 

export default RecipeEdit; 

回答

0

我認爲在更新列表後嘗試重新呈現時,實際上會出現錯誤。配方中的配料屬性是一個數組(如getRecipes()所示),但是您將配料的新狀態(在EditRecipe中)設置爲字符串:"egg,flour,salt,water",然後嘗試將配料渲染爲數組:ingredients.map()

當您使用數組呈現輸入字段<input value={["egg", "flour"]} />它確實顯示用逗號分隔的值,但onChange中的event.target.value實際上是一個字符串。

在EditRecipe的,handleIndChange可以固定:

this.setState({revisedRecipe: {ingredients: e.target.value.split(',')}}); 

這確實有一個問題,雖然你是完全重寫revisedRecipe。所以所有的setState電話應該是這樣的:

const recipe = this.state.revisedRecipe; 
recipe.ingredients = e.target.value.split(','); 
this.setState({revisedRecipe: recipe); 
+0

我試着改變handleIndChange。仍然不起作用。 –