简体   繁体   中英

Why does my add function not work?

I am trying to get the value the user inputs into the modal input boxes and then add them to my state array. I have tried to take the value from the inputs and then push them into a clone of my state array and then set the state to the clone. However, this approach does not seem to work. I would appreciate if anyone could chime in.

    var Recipes = React.createClass({
    // hook up data model
    getInitialState: function() {
      return {
        recipeList: [
            {recipe: 'Cookies', ingredients: ['Flour', 'Chocolate']},
            {recipe: 'Pumpkin Pie', ingredients: ['Pumpkin Puree', 'Sweetened Condensed Milk', 'Eggs', 'Pumpkin Pie Spice', 'Pie Crust']},
            {recipe: 'Onion Pie', ingredients: ['Onion', 'Pie-Crust']},
            {recipe: 'Spaghetti', ingredients: ['Noodles', 'Tomato Sauce', 'Meatballs']}
          ]
      }
    },

    ingredientList: function(ingredients) {
     return ingredients.map((ingredient, index) => {
      return (<li key={index} className="list-group-item">{ingredient}</li>)
     })
    },

    eachRecipe: function(item, i) {
      return (
          <div className="panel panel-default">
            <div className="panel-heading"><h3 key={i} index={i} className="panel-title">{item.recipe}</h3></div>
            <div className="panel-body">
              <ul className="list-group">
                {this.ingredientList(item.ingredients)}
              </ul>
            </div>
          </div>
      )
    },

    add: function(text) {
      var name = document.getElementById('name').value;
      var items = document.getElementById('ingredients').value.split(",");
      var arr = this.state.recipeList;
      arr.push({ recipe: name, ingredients: items });
      this.setState({recipeList: arr})
    },

    render: function() {
        return (
          <div>
          <div>
          <button type="button" className="btn btn-success btn-lg" data-toggle="modal" data-target="#myModal">Add Recipe</button>
          <div id="myModal" className="modal fade" role="dialog">
            <div className="modal-dialog">

            <div className="modal-content">
            <div className="modal-header">
          <button type="button" className="close" data-dismiss="modal">&times;</button>
            <h4 className="modal-title">Add a new recipe</h4>
            </div>
            <div className="modal-body">
            <form role="form">
                    <div className="form-group">
                      <label forName="recipeItems">Recipe</label>
                        <input ref="userVal" type="recipe" className="form-control"
                        id="name" placeholder="Enter Recipe Name"/>
                    </div>
                    <div className="form-group">
                      <label for="ingredientItems">Ingredients</label>
                        <input ref="newIngredients" type="ingredients" className="form-control"
                            id="ingredients" placeholder="Enter Ingredients separated by commas"/>
                    </div>
                    <button onClick={this.add} type="submit" className="btn btn-default">Submit</button>
                  </form>
            </div>
            <div className="modal-footer">
          <button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
          </div>
      </div>
      </div>
      </div>
          {
            this.state.recipeList.map(this.eachRecipe)
          }
          </div>
          </div>
        );
      }
  });

  ReactDOM.render(
    <Recipes />,
    document.getElementById('master')
  )

The problem is that whenever you click the button the form is submitted and the page reloads.

One solution is to take the onClick={this.add} out of the button and add onSubmit={this.add} at the <form> tag instead.

So, at the add() function you do:

add: function(e) {
  e.preventDefault();
  var form = e.target;
  var name = form.name.value;
  var items = form.ingredients.value.split(",");
  var arr = this.state.recipeList;
  arr.push({ recipe: name, ingredients: items });
  this.setState({recipeList: arr});
},

First, you call e.preventDefault() so your form won't reload the page. Second, you could use the target to access the input value through theirs name s attribute and set the state.

A few things that can be improved in your code.

  add: function(text) {
    ...
    arr.push({ recipe: name, ingredients: items });
    this.setState({recipeList: arr})
  }

By using the push() method on your array you are essentially modifying the component's state by pushing the new item into it. It's strongly advised that you don't mutate your React component's state directly without using the setState method .

A way to fix this would be by creating a new array in which you will copy all of the existing recipes plus the new recipe you are adding.

If you are using ES6/2015 it's even easier to achieve this:

add: function(text) {
  ...
  var newRecipe = { 
    recipe: name, 
    ingredients: items 
  };
  this.setState({ recipeList: [...this.state.recipeList, newRecipe] });
}

That way you don't modify the component's state before calling setState() method thus keeping it intact.

Next

add: function() {
  var name = document.getElementById('name').value;
  var items = document.getElementById('ingredients').value.split(",");
  ...
}

Try as much as possible to use the Refs (references) to access your input nodes, that way you don't have to use getElementById because it is more in line with the rest of your react code.

add: function(text) {
  var name = this.refs.userVal.value;
  var items = this.refs.newIngredients.value.split(",");
  ...
},
render: function() {
  return (
    <div>
      ...
        <input 
          ref="userVal" 
          placeholder="Enter Recipe Name"
        />
        <input 
          ref="newIngredients" 
          placeholder="Enter Ingredients separated by commas"
        />
      ...
    </div>
  );
});

And lastly

To prevent the Button element from submitting the form and taking you to another page, which is what happening here, you could set the button's type attribute to button and it should no longer submit the form. By default a button element is of type submit .

<button onClick={this.add} type="button" className="btn btn-default">Submit</button>

And so by doing this you won't need to "prevent" the default action from occurring (which is to submit the form), using the Event.preventDefault() method in your onClick function handler.

Here is a jsBin link with the above changes you could look at.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM