【问题标题】:Reactjs duplicates inserted object on previously inserted objectsReactjs 在先前插入的对象上复制插入的对象
【发布时间】:2016-12-22 06:23:00
【问题描述】:

我遇到了一个非常奇怪的案例,想看看是什么原因造成的。我正在制作一个食谱框,它可以包含 ReactJS 中的食谱。它从这些初始配方开始:

    var App = React.createClass({
  getInitialState: function() {
    return {
      recipes: [{
        id: 0,
        name: "Carbonana",
        ingredients: ["Spaghetti", "Banana-sauce", "Bacon", "Cream", "Oregano"]
      }, {
        id: 1,
        name: "Roasted duck with sweet potatoes",
        ingredients: ["Duck", "Sweet chili sauce", "Small potatoes", "Sugar", "Butter"]
      }, {
        id: 2,
        name: "Baked potatoes",
        ingredients: ["Baking potatoes", "Bacon", "Creme Fraiche", "Garlic", "Onions"]
      }]
    }
  }

然后,您可以通过添加您自己的食谱,其中包含名称和成分。表单。 在 AddRecipe 组件中:

 <Form >
  <ControlLabel>Recipe Name</ControlLabel>
            <FormControl
        type="text"
        value={this.state.value}
        placeholder="Beef Cheese"
        onChange={this.handleRecipeNameChange}
      />
  <hr/>
    <FormGroup controlId="formControlsTextarea">
  <ControlLabel>Ingredients</ControlLabel>
  <FormControl onChange={this.handleIngredientsChange}
 componentClass="textarea" placeholder="salt,pepper,cheese,beef" />
</FormGroup>
  <ButtonToolbar>
<Button onClick={this.handleAddRecipe} bsStyle="primary">Add Recipe</Button>
  <Button onClick={this.closeModal}>Cancel</Button>

成分可以用逗号分隔的形式输入。这是表单的句柄方法:

在 AddRecipe 组件中:

  handleAddRecipe: function() {
    this.closeModal();
    this.props.addRecipe(this.state.recipe);
  },

  handleRecipeNameChange: function(e) {
    var recipe = this.state.recipe;
    recipe.name = e.target.value;
    this.setState({recipe: recipe});
  },

  handleIngredientsChange: function(e) {
    var recipe = this.state.recipe;
    recipe.ingredients = e.target.value.split(",");
    this.setState({recipe: recipe});
  }

最后是 addRecipe(recipe),它从 AddRecipe 组件接收一个食谱并将其添加到食谱对象的食谱数组中。每个菜谱都应该有一个唯一的 ID:

  addRecipe: function(recipe) {
    var currentRecipes = this.state.recipes;
    console.log("currentRecipes ");
    console.log(currentRecipes);
    recipe.id = currentRecipes.length;
    currentRecipes.push(recipe);
    console.log("recipe added: ");
    console.log(recipe);
    console.log(recipe.id + " last id!");
    this.setState({recipes: currentRecipes});
  }

如果我添加 1 个配方,它的唯一 ID 为 3,这是输出,这很好,正如我所料:

    recipes: [{
        id: 0,
        name: "Carbonana",
        ingredients: ["Spaghetti", "Banana-sauce", "Bacon", "Cream", "Oregano"]
      }, {
        id: 1,
        name: "Roasted duck with sweet potatoes",
        ingredients: ["Duck", "Sweet chili sauce", "Small potatoes", "Sugar", "Butter"]
      }, {
        id: 2,
        name: "Baked potatoes",
        ingredients: ["Baking potatoes", "Bacon", "Creme Fraiche", "Garlic", "Onions"]
      }, {
        id: 3,
        name: "Something new and exciting!",
        ingredients: ["More beef", "Onions"]
      }]

现在我再次从 AddRecipe 组件打开表单,然后输入一个新的食谱。但这一次它只是再次插入相同的对象:

recipes: [{
            id: 0,
            name: "Carbonana",
            ingredients: ["Spaghetti", "Banana-sauce", "Bacon", "Cream", "Oregano"]
          }, {
            id: 1,
            name: "Roasted duck with sweet potatoes",
            ingredients: ["Duck", "Sweet chili sauce", "Small potatoes", "Sugar", "Butter"]
          }, {
            id: 2,
            name: "Baked potatoes",
            ingredients: ["Baking potatoes", "Bacon", "Creme Fraiche", "Garlic", "Onions"]
          }, {
            id: 4,
            name: "Something even more new and improved!!",
            ingredients: ["Day old potatoes", "salt"]
          }, {
            id: 4,
            name: "Something even more new and improved!!",
            ingredients: ["Day old potatoes", "salt"]
          }]

我注意到它在所有以前输入的对象中复制了最新输入的对象。为什么是这样?您可以在 http://codepen.io/Hylleh/pen/pbqNbO?editors=1010 上查看正在运行的页面

【问题讨论】:

  • 在您的代码中有几个点,您可以通过执行var currentRecipes = this.state.recipes; 之类的操作来改变状态对象本身,然后修改currentRecipes。用var currentRecipes = Object.assign([], this.state.recipes); 更改每个这样的语句,然后重试。

标签: javascript arrays list reactjs duplicates


【解决方案1】:

阻止您添加新配方的问题是您的 AddRecipe 组件正在使用 this.props.addRecipe 并将 reference 传递给其状态。

您的App 组件获取此引用,并一遍又一遍地将其添加到数组中。因此,该数组中索引 2 之后的每个项目将始终是对相同 AddRecipe 状态的完全相同的引用,这意味着它们将共享相同的 idnameingredients 属性。由于您使用 id 作为每个配方的键,因此 React 不会在您添加的第一个配方之后呈现任何配方,因为每个额外的配方都将与最后一个共享相同的键。

如果您在该页面上打开控制台,您会在尝试添加两个配方后看到此错误:

警告:flattenChildren(...):遇到两个孩子使用相同的密钥,4。子键必须是唯一的;当两个孩子共享一个密钥时,只会使用第一个孩子。

解决此问题的方法是避免将AddRecipe 组件状态的引用保存到App 组件状态。我会像这样修改App.addRecipe 函数:

addRecipe(recipe) {
    // Clone passed state reference and set id to the correct value
    const newRecipe = Object.assign({}, recipe, {
        id: this.state.recipes.length
    });

    // Replace recipes with a new array that has newRecipe appended at the end
    this.setState({
        recipes: [...this.state.recipes, newRecipe]
    });
}

【讨论】:

  • 非常感谢它现在可以工作了。我不知道我在传递参考。
  • 乐于提供帮助 :) 如果它解决了您的问题,请确保您接受答案!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-17
  • 1970-01-01
  • 2011-10-19
  • 2023-03-08
  • 2019-12-30
  • 2017-03-06
  • 1970-01-01
相关资源
最近更新 更多