如何使for循环在组件内的属性中工作

时间:2016-12-27 14:56:28

标签: javascript reactjs

这是一个应用程序,当点击添加配方按钮时,会弹出一个弹出窗口。这使您可以将配方名称和配方成分放入输入框中。按下该弹出框中的添加配方按钮应该呈现存储在localStorage中的配方名称。

现在我的Recipe列表使用一个名为list的空数组,并使用for循环将localStorage项添加到列表数组中。现在虽然它只适用于页面加载,而不是单击添加配方按钮时。这是因为它不能更新阵列,因为我目前在组件外部有它,但是放入它使它不加载任何列表项。

有问题的组件:

var React = require("react");

var Recipe = React.createClass({

    getInitialState: function() {
      return {
        list: ""
      };  
    },

    updateList: function() {
      var list = [];

      for (let i = 0; i < window.localStorage.length - 1; i++)  {      
         var key = window.localStorage.key(i);
         list.push(window.localStorage.getItem(key));         
      }

      this.setState({
        list: list
      });      
    },

    componentDidMount: function() {
      this.updateList();  
    },


    render: function() {
        return (
          <div className="full-recipe">
            {this.state.list.map(function(item) {
              return (
                <div className="recipe">
                  <h2>{item.name}</h2>
                </div>            
              );
            })}
            <button onClick={function() { this.updateList()}}>refresh the list</button>
          </div> 
        );
    }
});

module.exports = Recipe;

完整代码:https://github.com/jeffm64/recipe-box/blob/master/src/components/recipe.js

2 个答案:

答案 0 :(得分:0)

我检查了你的代码,你可以将popupbox.js中的addRecipe函数更改为:

addRecipe: function() {
  var recipeName = document.querySelector(".recipe-name").value;
  var counter = parseInt(window.localStorage.getItem("counter"));
  window.localStorage.setItem("counter", counter++);
  var recipes = window.localStorage.getItem("recipes");
  if (!recipes)
    recipes = [];
  else
    recipes = JSON.parse(recipes);
  recipes.push({name: recipeName});
  window.localStorage.setItem("recipes", JSON.stringify(recipes));
  this.updateList();
},

然后更新列表:

updateList: function() {
  var list = window.localStorage.getItem('recipes');
  if (list)
    list = JSON.parse(list);
  else
    list = [{}];        

  this.setState({
    list: list
  });      
},

并且不要忘记渲染功能中的键

{this.state.list.map(function(item, idx) {
  return (
    <div className="recipe" key={idx}>
      <h2>{item.name}</h2>
    </div>            
  );
})}

答案 1 :(得分:0)

最好将所有localStorage访问保存在父组件中的一个位置,然后使用props将其传播下来。

子组件(如“弹出”)可以通过道具接收回调函数,以向上传播某些内容。

这篇官方文章精美地解释了这一点:

https://facebook.github.io/react/docs/thinking-in-react.html

这是一个非常简单的例子:

http://codepen.io/anon/pen/MbMrdL?editors=1010

class App extends React.Component{

  constructor(props){
    super(props)
    this.state = {recipes:[]}
    this.loadRecipes = this.loadRecipes.bind(this)
    this.addRecipe = this.addRecipe.bind(this)
    this.deleteAllRecipes = this.deleteAllRecipes.bind(this)
  }

  loadRecipes(){
    const storedRecepes = window.localStorage.getItem('recipes')
    const recipes = storedRecepes?JSON.parse(storedRecepes):[]
    this.setState({recipes:recipes}) 
  }
  addRecipe(recipe){
    const recipes = [...this.state.recipes, recipe]
    this.setState({recipes:recipes})
    window.localStorage.setItem('recipes',JSON.stringify(recipes))
  }
  deleteAllRecipes(recipe){
    this.setState({recipes:[]})
    window.localStorage.setItem('recipes',JSON.stringify([]))
  }

  componentWillMount(){
    this.loadRecipes()
  }

  render(){
    return (
      <div>
        <RecipesList recipes={this.state.recipes} />
        <RecipeAdd onRecepeAdded={this.addRecipe} />
        <RecipeDeleteAll onRecepesDeleted={this.deleteAllRecipes} />
        </div>
    )
  }
}

class RecipesList extends React.Component{
  render(){
    return (
      <div>
        <h1>Recipes</h1>
        <ul>
          {this.props.recipes.map((recipe, idx)=>
            <li key={idx}>{recipe.name}</li>
           )}
         </ul>
      </div>)
  }
}

class RecipeAdd extends React.Component{

  add(){
    const name = window.prompt("recepe name:")
    this.props.onRecepeAdded({name:name})
  }

  render(){
    return <button onClick={this.add.bind(this)}>Add</button>
  }
}

class RecipeDeleteAll extends React.Component{

  deleteAll(){
    if(confirm('Delete all?')){
      this.props.onRecepesDeleted()
    }
  }

  render(){
    return <button onClick={this.deleteAll.bind(this)}>Delete All</button>
  }
}

ReactDOM.render(<App/>,document.getElementById('root'))