Implementing localStorage in my React application

泄露秘密 提交于 2020-01-05 05:37:48

问题


I'm currently doing the freeCodeCamp React challenge Building a Recipe Box. I have to fulfil the User Story of using HTML5 web storage to save changes made by the user so that even when the page is refreshed the changes remain. However I built my React Application without planning this beforehand , and now I'm stuck in a situation where I don't know how to add this functionality to my app.

P.S I tried using global variables and setting state along with setting local storage . I'm new to React.

/*-------------------------------------------------------------------------*/
var RecipeEdit = React.createClass({
  getInitialState: function() {
    return {
      titleOne: 'Sakkarai Pongal Recipe (Sweet Pongal Recipe)',
      urlOne: 'https://4.bp.blogspot.com/-a1NWFkB9xLU/U1Er4eD_vlI/AAAAAAAAd-w/tUECZ8OUCKw/s1600/sakkarai+pongal+recipe.jpg',
      contentOne: 'Ingredients: Raw rice - 1 cup,Mung bean - 2 to 4 tbsp,Jaggery - 1 cup,Clarified butter - 1/4 cup (can adjust as per preference),Cardamom - 1,Water for cooking rice - 6 cups,Milk - 2 tbsp,Water for jaggery syrup - 1/2 cup,Edible camphor - mustard seed size,Clove - 1,Nutmeg powder- a pinch ,Salt - a pinch (optional),Cashews, raisins - 1 tbsp each',

      titleTwo: 'Medhu Vadai / Ulundu Vadai Recipe',
      urlTwo: 'https://3.bp.blogspot.com/-7qyx9n0Wyxo/UKC3ECH8QGI/AAAAAAAAbs4/WN-0u5cVUxU/s1600/Ulundhu-vadai--Medhu-vadai.jpg',
      contentTwo: 'Ingredients: Black lentil - 3/4 cup,Small onion, shallots(or Big onion – 1) - 10 ,Green pimento pepper - 2 ,Ginger - 1 inch piece,Coriander leaves - 2 tblp, chopped.,Curry leaves - A sprig,Asafoetida - 3-4 pinches,Salt - As needed,Water - As needed',

      titleThree: 'Neer Mor (Recipe For Spiced Buttermilk)',
      urlThree: 'http://farm9.staticflickr.com/8244/8638427263_fc66ac04a3_z.jpg',
      contentThree: 'Ingredients: Plain yogurt - 1 cup,Water - 4 cups,Green pimento pepper - 2,Chopped ginger - 1 tblsp,Chopped cilantro - 1 tblsp,Chopped curry leaves - 1 sprig,Salt - As needed,Asafoetida - 1 pinch,Lemon(optional) - 1/2'
    };
    //localStorage.setItem('Furball_Default', //JSON.stringify(this.state));
  },

 /* componentWillMount: function() {
    var PreviousData = JSON.parse(localStorage.getItem('Furball_Default'));
    if (PreviousData) {
      this.setState({
        [this.state]: PreviousData
      });
    }
  },*/

  handleTitle1Change: function(event) {
    this.setState({
      titleOne: event.target.value
    });
   // localStorage.setItem('Furball_Default', //JSON.stringify(this.state));
  },

  handleTitle2Change: function(event) {
    this.setState({
      titleTwo: event.target.value
    });
   // localStorage.setItem('Furball_Default', //JSON.stringify(this.state));
  },

  handleTitle3Change: function(event) {
    this.setState({
      titleThree: event.target.value
    });
   // localStorage.setItem('Furball_Default', //JSON.stringify(this.state));
  },

  handleUrl1Change: function(event) {
    this.setState({
      urlOne: event.target.value
    });
    //localStorage.setItem('Furball_Default', //JSON.stringify(this.state));
  },

  handleUrl2Change: function(event) {
    this.setState({
      urlTwo: event.target.value
    })
  },

  handleUrl3Change: function(event) {
    this.setState({
      urlThree: event.target.value
    });
    //localStorage.setItem('Furball_Default', //JSON.stringify(this.state));
  },

  handleContent1Change: function(event) {
    this.setState({
      contentOne: event.target.value
    });
   // localStorage.setItem('Furball_Default', //JSON.stringify(this.state));
  },

  handleContent2Change: function(event) {
    this.setState({
      contentTwo: event.target.value
    });
   // localStorage.setItem('Furball_Default', //JSON.stringify(this.state));
  },

  handleContent3Change: function(event) {
    this.setState({
      contentThree: event.target.value
    });
    //localStorage.setItem('Furball_Default', //JSON.stringify(this.state));
  },

  render: function() {
    return (<section> 
              <div className="card small horizontal pink lighten-4 z-depth-4">
               <div className="card-image waves-effect waves-block waves-light">
                <img className="activator" src={this.state.urlOne} /> 
    </div>
      
    <div className="card-content">
      <span className="card-title activator grey-text text-darken-4">{this.state.titleOne}</span>
    </div><a className="waves-effect waves-light btn red z-depth-5 del">Delete &nbsp;<span className="fa fa-trash-o fa-lg"> </span></a>
    <div className="card-reveal">
      <span className="card-title"><i className="material-icons right">close</i></span> <div className="input-field inline">
          <input type="text" onChange={this.handleTitle1Change} value={this.state.titleOne} /> 
          <label htmlFor="title">Title</label>
        </div> &nbsp; <div className="input-field inline">
          <input type="text" onChange={this.handleUrl1Change} value={this.state.urlOne} /> 
          <label htmlFor="url">Image URL</label>
        </div><div className="input-field">
      <textarea type="text" className="materialize-textarea" onChange={this.handleContent1Change} value={this.state.contentOne} /> <label>Ingredients/Directions </label> </div>
    </div>
      </div> 
     <div className="card small horizontal brown lighten- z-depth-4">
    <div className="card-image waves-effect waves-block waves-light">
      <img className="activator" src={this.state.urlTwo} /> 
    </div>  
    <div className="card-content">
      <span className="card-title activator grey-text text-darken-4">{this.state.titleTwo}</span>
    </div>
       <a className="waves-effect waves-light btn red z-depth-5 del">Delete &nbsp;<span className="fa fa-trash-o fa-lg"> </span></a>
    <div className="card-reveal">
      <span className="card-title"><i className="material-icons right">close</i></span> <div className="input-field inline">
          <input type="text" onChange={this.handleTitle2Change} value={this.state.titleTwo} /> 
          <label htmlFor="title">Title</label>
        </div> &nbsp; <div className="input-field inline">
          <input type="text" onChange={this.handleUrl2Change} value={this.state.urlTwo} /> 
          <label htmlFor="url">Image URL</label>
        </div><div className="input-field">
      <textarea onChange={this.handleContent2Change} type="text" className="materialize-textarea" value={this.state.contentTwo} /> <label>Ingredients/Directions </label> </div>
    </div>
      </div>  
       
  <div className="card small horizontal lime z-depth-4">
    <div className="card-image waves-effect waves-block waves-light">
      <img className="activator" src={this.state.urlThree} /> 
    </div>  
    <div className="card-content">
      <span className="card-title activator grey-text text-darken-4">{this.state.titleThree}</span>
    </div><a className="waves-effect waves-light btn red z-depth-5 del">Delete &nbsp;<span className="fa fa-trash-o fa-lg"> </span></a>
    <div className="card-reveal">
      <span className="card-title"><i className="material-icons right">close</i></span> <div className="input-field inline">
          <input type="text" onChange={this.handleTitle3Change} value={this.state.titleThree} /> 
          <label htmlFor="title">Title</label>
        </div> &nbsp; <div className="input-field inline">
          <input type="text" onChange={this.handleUrl3Change} value={this.state.urlThree} /> 
          <label htmlFor="url">Image URL</label>
        </div><div className="input-field">
      <textarea onChange={this.handleContent3Change} type="text" className="materialize-textarea" value={this.state.contentThree} /> <label>Ingredients/Directions </label> </div>
    </div>
      </div>  <Form />      
      </section>);
  }
});
/*-------------------------------------------------------------------------*/

var Form = React.createClass({
  getInitialState: function() {
    return {
      title: '',
      url: '',
      content: '',
      clicked: false,
      newCardArr: []
    };
  },

  updateT: function(val) {
    this.setState({
      title: val.target.value
    });
    console.log(this.state.title);
   // localStorage.setItem('Furball_New', //JSON.stringify(this.state));
  },

  updateU: function(val) {
    this.setState({
      url: val.target.value
    });
    console.log(this.state.url);
    //localStorage.setItem('Furball_New', //JSON.stringify(this.state));
  },

  updateC: function(val) {
    this.setState({
      content: val.target.value
    });
    console.log(this.state.content);
   // localStorage.setItem('Furball_New', //JSON.stringify(this.state));
  },

  onClick: function() {
    this.setState({
      clicked: true,
      newCardArr: [<Create key={Math.random()} title={this.state.title} url={this.state.url} content={this.state.content} />, ...this.state.newCardArr]
    });
  },

  render: function() {
    return (<div>  {this.state.clicked ? this.state.newCardArr : null}
      <div className="center-align">
                <ul className="collapsible" data-collapsible="accordion">
    <li> 
      <div className="collapsible-header btn-floating btn-large waves-effect waves-light red z-depth-5"><i className="material-icons">edit</i> </div><h6>Add New Recipe </h6> 
      <div className="collapsible-body"><span><div className="input-field inline">
          <input id="title" type="text" onChange={this.updateT}/> 
          <label className="cyan-text" htmlFor="title">Title</label>
        </div> &nbsp; <div className="input-field inline">
          <input type="text" onChange={this.updateU} /> 
          <label className="cyan-text" htmlFor="url">Image URL</label>
        </div><div className="input-field">
      <textarea type="text" className="materialize-textarea" onChange={this.updateC} /> <label className="cyan-text">Ingredients/Directions </label> </div><button className="btn waves-effect waves-light z-depth-5" onClick={this.onClick} type="submit" name="action">Submit
    <i className="material-icons right">send</i>
  </button> </span></div>
    </li>
    </ul> </div> </div>)

  }
});
/*-------------------------------------------------------------------------*/

var Create = React.createClass({
  getInitialState: function() {
    return {
      title: '',
      url: '',
      content: ''
    };
  },

  componentWillMount: function() {
    this.setState({
      title: this.props.title,
      url: this.props.url,
      content: this.props.content
    });
   /* var PreviousData = JSON.parse(localStorage.getItem('Furball_New'));
    if (PreviousData) {
      this.setState({
        [this.state]: PreviousData
      });
    }*/
  },

  onChange: function(event) {
    this.setState({
      [event.target.id]: event.target.value
    });
   // localStorage.setItem('Furball_New', //JSON.stringify(this.state));
  },

  render: function() {
    console.log(this.state);
    return (<div className="card small horizontal z-depth-4"><div className="card-image waves-effect waves-block waves-light">
      <img className="activator" src={this.state.url} /> 
    </div> <div className="card-content">
      <span className="card-title activator grey-text text-darken-4">{this.state.title}</span>
    </div><a className="waves-effect waves-light btn red z-depth-5 del">Delete &nbsp;<span className="fa fa-trash-o fa-lg"> </span></a><div className="card-reveal">
      <span className="card-title"><i className="material-icons right">close</i></span> <div className="input-field inline">
          <input type="text" id="title" value={this.state.title} onChange={this.onChange} /> 
          <label htmlFor="title">Title</label>
        </div> &nbsp; <div className="input-field inline">
          <input type="text" id="url" onChange={this.onChange} value={this.state.url} /> 
          <label htmlFor="url">Image URL</label>
        </div><div className="input-field">
      <textarea type="text" className="materialize-textarea" id="content" onChange={this.onChange} value={this.state.content} /> <label>Ingredients/Directions </label> </div>
    </div></div>);

  }
});
/*-------------------------------------------------------------------------*/

ReactDOM.render(<RecipeEdit />, document.getElementById('app'));
/*-------------------------------------------------------------------------*/
// var recipes = [];
/*componentWillMount: function() {
    var PreviousData = JSON.parse(localStorage.getItem('Furball_RecipesBox'));
    if (PreviousData) {
      this.setState({
        [this.state]: PreviousData
      });
    }
  },
  
  componentDidUpdate: function(prevProps, prevState) {
    localStorage.setItem('Furball_RecipesBox', JSON.stringify(this.state));
  },*/
/* <div>var recipes = []; array={recipes}
            <Button onClick={this.handleClick} />
        var array= [this.props.array];
    array.push(this.state);     
          </div>*/
// setTimeout(this.after, 5000);
// setTimeout( this.setState({
//   clicked: true
//  }),6000)
//e.preventDefault();
//console.log(this.props.array);
/* componentWillMount: function() {
    var PreviousData = JSON.parse(localStorage.getItem('Furball_RecipesBox'));
    if (PreviousData) {
      this.setState({
        [this.state]: PreviousData
      });
    }
  },

  componentWillUnmount: function() {
    this.setState({
      [this.props.array]: this.state
    });
    console.log(this.props.array);
    localStorage.setItem('Furball_RecipesBox', JSON.stringify(this.props.array)); 
  }, */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  background-image: url("http://cdn.backgroundhost.com/backgrounds/subtlepatterns/retina_wood.png");
}

#app {
  margin: 15px;
}

.card {
  border-radius: 7%;
}

.del {
  margin-right: 15px;
  margin-top: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/js/materialize.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/css/materialize.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"> </div>

回答1:


I think the main problem with your code is the assumption that you can access this.state immediately after calling this.setState and it will contain the updated values.

This is not the case, here is why:

setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.

Therefore I advice you to use second argument and save state to the localstorage in it, something like this:

this.setState({
    titleOne: event.target.value,
  },
  () =>
  {
    localStorage.setItem('Furball_Default', JSON.stringify(this.state));
});


来源:https://stackoverflow.com/questions/42714648/implementing-localstorage-in-my-react-application

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!