React: Permanently store user input as the value - reactjs

I currently have the user input being updated by state and stored as the value however whenever the user directs to another page, closes the page or refreshes it, the value disappears. I want to permanently store the value there until the user changes their input.
Would I need to use persistent state for this? How can I permanently store the value of the user input until the user changes it?
class Planning extends React.Component {
constructor() {
super()
this.state = {
title: '',
goal: '',
tech: '',
features: '',
details: ''
}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange(event) {
this.setState({
[event.target.name]: event.target.value
})
}
handleSubmit(event) {
const {
title,
goal,
tech,
features,
details
} = this.state;
event.preventDefault();
this.setState({ title, goal, tech, features, details });
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<div>
<label className="label-title">
Project Title:</label>
<input name="title" id="title" type="text" value={this.state.title} onChange={this.handleChange} required aria-required="true"/>
</div>

Change your handleChange function to:
handleChange(event) {
const { value, name } = event.target
localStorage[name] = value
this.setState({
[name]: value
})
}
and your constructor to:
constructor() {
super()
this.state = {
title: localStorage["title"],
goal: '',
tech: '',
features: '',
details: ''
}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
This is not very elegant but will work. Alternatively you can save to localStorage on unmount.

Yes, you would have to manage this with a state management lib. Localstorage is too extreme. Plus the state management will come handy for other stuff in your app as it grows so i suggest you start right. You can look at mobx or redux.

Saving to localStorage is a synchronous operation , so we don't need to sync the local state to localStorage every time state variable changes as React already keeps the track of the application state in the user's session . You need to persist it in localStorage when user leaves page / refreshes. Save to localStorage on componentWillUnmount and window.onbeforeunload events. There is the a storage component that handles everything : https://github.com/ryanjyost/react-simple-storage

Related

React Form single handleChange function with multiple inputs and setState to complex object

I have a form inside a React component that has several inputs, representing properties of an object, defined in the component's state. I would like to make a POST request to my REST API by which I want to create an entity, by passing the filled in object from this.state, which in turn is modified by the form inputs.
I am unable to figure out how to use single handleChange() method to update the state on an onChange event of all the fields. I refereed to articles describing this problem but without complex types. I even tried to implement the dynamic key name by using [event.target.name] and adding name attribute to all of my form inputs but with no result.
Here is my code.
Component constructor and state:
class IngredientForm extends React.Component {
constructor(props) {
super(props);
this.apiService = new apiService();
this.state = {
ingredient: {
id: "",
name: "",
dateAdded: "",
}
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
}
handleChange and handleSubmit methods:
handleChange(event) {
const ingredient = this.state.ingredient;
ingredient[event.target.name] = event.target.value;
this.setState({ ingredient: ingredient });
}
handleSubmit(event) {
//Fetch code goes here
let response = this.apiService.postDataAsync("https://localhost:5001/api/ingredients",this.state.ingredient);
this.setState({ingredient:{id: response.id, dateAdded: response.dateAdded}});
event.preventDefault();
}
And this is the code of the form:
<form onSubmit={this.handleSubmit}>
<label>
Name
</label>
<input
type="text"
name="name"
value={this.state.ingredient.name}
onChange={this.handleChange}
required
/>
<label>Date added</label>
<input
type="date"
name="dateAdded"
value={this.state.ingredient.dateAdded}
onChange={this.handleChange}
/>
<button type="submit" value="Submit">
Save
</button>
</form>
I will be glad to receive your help. I tried to find a similar topic in the forum beforehand, but without success, everyone discussed the situation with primitive types in the state.
hey there the problem is in your set state can you tru this?
handleChange(event) {
const {name, value} = event.target;
this.setState({
ingredient: {
...this.state.ingredient,
[name]: value
}
});
}

React app, after getting data from initial get request, onChange doesnt work

constructor (props) {
super(props)
this.state = {
AyarAdi: '',
Bilgi: '',
FirmaKodu: '',
icerik: {
smsUser: '',
smsApi: '',
mesajAciklama: '',
password: ''
},
errors: {}
}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
componentDidMount () {
this.props.AyarlarListesiAl(this.props.user.userCreds.FirmaKodu)
}
handleChange (event) {
this.setState({
icerik: {
...this.state.icerik,
[event.target.name]: [event.target.value]
}
})
}
render(){
<div>
<InputGroup className='mb-3'>
<FormControl
name='password'
placeholder='SMS Şifre'
onChange={this.handleChange}
value={
this.props.data.AyarlarListesi[0] !== undefined
? JSON.parse(this.props.data.AyarlarListesi[0].Bilgi).password
: this.state.icerik.password
}
style={{ maxWidth: 400, height: 40 }}
/>
<span style={{ color: 'red' }}>
{this.state.errors['password']}
</span>
</InputGroup>
</div>
}
const mapStateToProps = state => ({
user: state.user,
data: state.data
})
....
The problem is, in componentDidMount, I send a get request to the server via Redux action, and it gets me data from the redux reducer state; AyarlarListesi. I wanted to fetch the data to the input elements value, So when a user opens the page, he/she can update the previous data just changing it on the input and clicks to submit. I can successfully put the data to the input but I can't change the value of the input, it stays stable, the handleChange function doesn't work. How can I make it work?
Your handleChange function only manipulates the state. However the value to be displayed comes preferrably from props and only if the props field is not available it will fall back to the state variable.
To display the state variable after changing it via user input, you could either swap the condition and make it so the state variable will be displayed unless it's empty (and use the props variable as a fallback) or you could instead update the state variable initially when you get new props.
Assuming you never change props from outside or don't care about later updates, this would be my preferred way of solving your problem:
componentDidMount () {
this.props.AyarlarListesiAl(this.props.user.userCreds.FirmaKodu);
if (this.props.data.AyarlarListesi[0] !== undefined) {
this.setState({
icerik: {
...this.state.icerik,
password: JSON.parse(this.props.data.AyarlarListesi[0].Bilgi).password,
},
});
}
}
Also in your FormControl skip checking if the props data is set and instead always use this.state.icerik.password as the value.
If your props from outside could change and you'd like to restart whenever a new password or AyarlarListesi is passed from outside, you should update the state in componentDidUpdate again:
componentDidUpdate (prevProps) {
if (prevProps.data.AyarlarListesi !== props.data.AyarlarListesi && props.data.AyarlarListesi[0] !== undefined) {
this.setState({
icerik: {
...this.state.icerik,
password: JSON.parse(this.props.data.AyarlarListesi[0].Bilgi).password,
},
});
}
}

How would I lift state in this small randomizer so that I can have it as a component?

I am using this small app to enter names and then randomly picking names from the array when it is fully entered. From what I can understand, I should lift the state from the inputs in to the parent class component. Further than that, can I abstract the JSX into a separate file and import it after the state has been moved to the parent?
I am very new to this so I am confused at how to do this in a way that makes sure everything still works. Essentially, I would want to just be able to have a component called in the main instance and give props that would share the state with the component and then be able to pass the updated state from the component to the parent. Is that possible? I am very confused and would love any help and solutions.
class App extends Component {
constructor() {
super();
this.state = {
value: '',
name: []
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleEnter = this.handleEnter.bind(this);
this.handleRandomize = this.handleRandomize.bind(this);
}
handleChange(e) {
this.setState({
value: e.target.value
})
}
handleSubmit() {
this.setState({
value: '',
name: this.state.name.concat(this.state.value)
})
console.log(this.state.name);
}
handleEnter(e) {
if (e.key === 'Enter') {
this.handleSubmit();
}
}
handleRandomize() {
let randVal = this.state.name;
let speaker = randVal[Math.floor(Math.random() * randVal.length)];
console.log(speaker);
}
render(){
return (
<div>
<input type='text' value={this.state.value} onChange={this.handleChange} onKeyPress={this.handleEnter}/>
<br></br>
<button onClick = {this.handleSubmit}>Submit Name</button>
<button onClick = {this.handleRandomize}>Randomize!</button>
<ul>{this.state.name.map((names) => <li key={names.toString()}>{names}</li>)}</ul>
</div>
)
}
};

Unable to save input picture data in state variable React.js

i'm trying to learn how the image upload process works with react. i have an input that takes image data in and a handler that sets that information to a variable but i am doing something incorrect and not sure what it is.
I want to update picture in state with the picture information and leave the other items in state alone. When i do the below, and console.log after the state of picture stays null.
class Profile extends Component {
constructor() {
super();
this.state = {
userName: "",
userEmail: "",
picture: null
};
this.handleNewImage = this.handleNewImage.bind(this);
}
handleNewImage = event => {
this.setState({
picture: event.target.files[0]
})
console.log(this.state.picture); //gives null still
}
render() {
return (
<input type='file' onChange={this.handleNewImage} />
);
}
}
This probably has nothing to do with images but rather an understanding of setState. React's setState is an async operation so you'd need to console log once the state update is complete:
handleNewImage = event => {
this.setState({
picture: event.target.files[0]
}, () => {
console.log(this.state.picture);
});
}
More info here:
https://reactjs.org/docs/react-component.html#setstate
https://css-tricks.com/understanding-react-setstate/

function onHandleChange won't work until after I've selected both options in the select tag

The function onHandleChange won't work until after I've selected both options in the select tag, then it start to work properly.I'm trying to render a chart based on which data the function gets. I'm curious to understand why this happens and where I'm making my mistake. Could someone please point to me where I'm making my mistake or if there's any mistake at all? I'm fairly new to React.js and programming in general.
This doesn't seemed to work until after I've selected both options from the select tag:
onHandleChange = (data, listDataFromChild) => {
if(this.state.listDataFromChild === 'oneYear'){
this.setState({
data:oneYear
})
} else if(this.state.listDataFromChild === 'twoYear'){
this.setState({
data:twoYear
})
}
}
Here's the component from which the function onHandleChange gets it's data from:
export class SelectionBoxYear extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 'oneYear'
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.setState({
value: e.target.value
},()=>{
let { value } = this.state;
this.props.callbackFromParent(value);
this.props.onHandleChange(value, this.props.dataFromParent)
});
}
render() {
return(
<div>
<label>
<p>Select the year of the investment:</p>
<select value={this.state.value} onChange={this.handleChange}>
<option value="oneYear">One year ago</option>
<option value="twoYear">Two years ago</option>
</select>
</label>
</div>
)
}
}
Here's the full code: https://github.com/vtrpza/chart/tree/master/my-app/src
From React's documentation
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. There is no
guarantee of synchronous operation of calls to setState and calls may
be batched for performance gains.
In SelectionBoxYear.js file you need to put the onHandleChange and callbackFromParent functions in the callback of set state
handleChange(e) {
this.setState({
value: e.target.value
},()=>{
let { value } = this.state;
this.props.callbackFromParent(value);
this.props.onHandleChange(value, this.props.dataFromParent)
});
}

Resources