Как заставить цикл for работать в свойстве внутри компонента

Это приложение, которое при нажатии кнопки добавить рецепт, вызывает всплывающее окно. Это позволяет поместить имя рецепта и ингредиенты рецепта в поля ввода. Нажатие кнопки добавить рецепт в этом всплывающем окне должно отобразить имена рецептов, которые были сохранены в localStorage.

Прямо сейчас мой список рецептов использует пустой массив с именем list и использует цикл for для добавления элементов localStorage в массив list. Прямо сейчас, хотя он работает только при загрузке страницы, не при нажатии на кнопку добавить рецепт. Это потому, что он не в состоянии обновить массив, так как в настоящее время у меня есть его за пределами компонента, но положить его в сделал его не загружать какие-либо элементы списка.

компонент в вопросе:

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 ответа

  1. я проверил ваш код, вы можете изменить функцию addRecipe в popupbox.js к этому:

    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:

    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>            
      );
    })}
    
  2. Лучше держать весь доступ к localStorage в одном месте, в Родительском компоненте, и распространять его вниз с помощью реквизитов.

    Дочерний компонент (например, ваш ‘pop up’) может получить функцию обратного вызова через реквизит, чтобы распространить что-то обратно вверх.

    Эта официальная статья объясняет это красиво:

    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'))