Reputation: 313
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 <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> <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 <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> <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 <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> <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> <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 <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> <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>
Upvotes: 1
Views: 178
Reputation: 22332
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));
});
Upvotes: 1