2017-08-03 21 views
1

私はレシピ帳アプリで作業中で、編集入力機能を実装しようとしています。 レシピ名(例:Pasta)を入力し、次に成分(例:卵、小麦粉、塩)を入力します。成分はコンマで入力する必要があり、リストとして表示されます。親レシピ帳にデータを渡す反応

  • パスタ
  • -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は実際には文字列です。その中で、あなたが完全にrevisedRecipeをオーバーライドしているものの、

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

これは別の問題を持っている:EditRecipeので

handleIndChangeを用いて固定することができます。したがって、 setStateのすべての呼び出しは、次のようなものでなければなりません。

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

私はhandleIndChangeを変更しようとしました。まだ動作しません。 –

関連する問題