Why is the setState not reloading the page with new data?

Once the user has entered a new recipe, the page needs to reload, loop through the list of recipes, and display the latest list. I know this has to be triggered with setState, which I am using. Why is it not triggering the reload?

(To see my CodePen for this, go here)

var GenerateRecipesFromList= React.createClass({
    getInitialState: function(){
      const defaultData = ['Spaghetti: pasta, oil, sauce, parsely, cheese', 'PB&J: PB, J']
      const localData = JSON.parse(localStorage.getItem('reclist'));
      return {
        reclist: localData ? localData : defaultData
      }
      
    },
  
   componentDidMount: function(){
      this.loadData();
   },

    exposeAddRecipe: function(){
      var exposeCurrentData = [];
      exposeCurrentData = JSON.parse(localStorage.getItem('reclist'));
      var newrecipe = prompt("Please add your next recipe", "For example, write 'PB&J: Peanutbutter, jelly, bread.'");
      exposeCurrentData.push(newrecipe);
      console.log(exposeCurrentData);
      this.loadData();
    },
     
    loadData: function(){
      return this.setState(localStorage.setItem('reclist', JSON.stringify(this.state.reclist)));
   },

    render: function(){
      //localStorage.setItem('reclist', JSON.stringify(this.state.reclist));
      var currentData = JSON.parse(localStorage.getItem('reclist'));
      var rows = [];
      for(var i=0; i<currentData.length; i++){
          rows.push(<div id="individual"> <span>{this.state.reclist[i]}</span> <button type="button" id="btnAdd">Edit Recipe</button>
        </div>);
        }
      return(
        <div>{rows}
        <button type="button" id="btnAdd" onClick={this.exposeAddRecipe}>Add Recipe</button>
          </div>
       );    
    }
  });

var Footer = React.createClass({
    render() {
    return (
      <footer>
        <div id="containerfooter">
          <p>Written by <a href="http://codepen.io/profaneVoodoo/full/dXBJzN/">John Gillespie</a> for FreeCodeCamp Campers. Happy Coding!</p>
       </div>
      </footer>
    );
  }
  });

var DisplayRecipes = React.createClass({
  render:function(){
    return(
      <div className = "mainDiv">
          <div className="titleDiv">
        <h1>Favorite Recipes</h1>
            <GenerateRecipesFromList />
            <Footer />
          </div>        
        </div>
    );
  }
});

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

setState should look like this:

this.setState({
  key: value
})

and you are using setItem inside setState, so your setState in reality looks like this:

return this.setState()

(localStorage.setItem has no return value)

Thanks!

Got it working now!

var GenerateRecipesFromList= React.createClass({
   getInitialState: function(){
      const defaultData = ['Spaghetti: pasta, oil, sauce, parsely, cheese', 'PB&J: PB, J']
     const localData = JSON.parse(localStorage.getItem('reclist'));
      return {
        reclist: localData ? localData : defaultData
      }
  
    },

    exposeAddRecipe: function(){
      var exposeCurrentData = [];
      exposeCurrentData = JSON.parse(localStorage.getItem('reclist'));
      var newrecipe = prompt("Please add your next recipe", "For example, write 'PB&J: Peanutbutter, jelly, bread.'");
      exposeCurrentData.push(newrecipe);
      localStorage.setItem('reclist', JSON.stringify(exposeCurrentData));
      this.setState({ reclist: exposeCurrentData})
    },

    render: function(){
     var testData = JSON.parse(localStorage.getItem('reclist'));

      if(testData === null){
     localStorage.setItem('reclist', JSON.stringify(this.state.reclist));
        }
      var currentData = JSON.parse(localStorage.getItem('reclist'));
      var rows = [];
      for(var i=0; i<currentData.length; i++){
          rows.push(<div id="individual"> <span>{this.state.reclist[i]}</span> <button type="button" id="btnAdd">Edit Recipe</button>
        </div>);
        }
      return(
        <div>{rows}
        <button type="button" id="btnAdd" onClick={this.exposeAddRecipe}>Add Recipe</button>
         </div>
       );    
   }
  });

var Footer = React.createClass({
    render() {
   return (
     <footer>
        <div id="containerfooter">
          <p>Written by <a href="http://codepen.io/profaneVoodoo/full/dXBJzN/">John Gillespie</a> for FreeCodeCamp Campers. Happy Coding!</p>
        </div>
      </footer>
    );
  }
  });

var DisplayRecipes = React.createClass({
  render:function(){
    return(
      <div className = "mainDiv">
          <div className="titleDiv">
        <h1>Favorite Recipes</h1>
            <GenerateRecipesFromList />
            <Footer />
          </div>        
        </div>
    );
  }
});

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

A declarative approach I have come to prefer (abbreviated HTML):

currentData.map(function(item, i) {
  return <div><span>{this.state.reclist[i]}</span><button></button></div>;
});

It lets you skip the boring work of iterating an array and instead apply a function to each item.

Actually, I just noticed you’re iterating on currentData, but you only reference this.state.reclist in your loop. Is this by design?

Yes. At the time it was just a quick and dirty way to get the number of iterations I needed, though my senses are telling me it may cause problems down the road.

Being a newbie to React I have not seen that approach you are taking with currentData. But it makes sense now that I see it and I will definitely incorporate it in the final version.

I have since forked the codepen and the latest version is here.

1 Like