onChange or onKeyUp event takes previous value in ReactJS - reactjs

I've created form in ReactJS. I am fetching value in common method in {key : value} paired. but I am getting previous value in method.
constructor(props) {
super(props);
{
this.state = { name: "", age: 0 };
}
}
inputChange = (key, value) => {
this.setState({ [key] : value });
console.log(this.state);
}
render() {
return (
<form>
<div>
Name : <input type="text" name="name" onKeyUp={(e) => this.inputChange('name', e.target.value)}></input>
</div>
<div>
Age : <input type="text" name="age" onKeyUp={(e) => this.inputChange('age', e.target.value)}></input>
</div>
</form>
)
}
I've attached the screenshot for better understanding.

setState enqueues a change to the state, but it doesn't happen immediately. If you need to do something after the state has changed, you can pass a second callback argument to setState:
inputChange = (key, value) => {
this.setState({ [key] : value }, () => {
console.log(this.state);
});
}

This will do exactly what you need.
class App extends Component {
constructor(props){
super(props)
this.state = {
name: '',
age: ''
}
}
handleInput(option, event){
if (option === 'name') {
this.setState({
name: event.target.value
}, () => {
console.log("Name: ", this.state.name)
});
}
else if (option === 'age'){
this.setState({
age: event.target.value
}, () => {
console.log("Age: ", this.state.age)
});
}
}
render() {
return (
<div>
<div>
<header>Name: </header>
<input type="text" onChange={this.handleInput.bind(this, 'name')}/>
<header>Age: </header>
<input type="text" onChange={this.handleInput.bind(this, 'age')}/>
</div>
</div>
);
}
}

update 2022
with functional components using useState hook this does not work longer, you have to use it in useEffect to update after rendering.
State updates from the useState() and useReducer() Hooks don't support the second callback argument. To execute a side effect after rendering, declare it in the component body with useEffect().

Related

calling function in React SetState gives error that userName is unlabelled why?

import React,{Component} from 'react'
class Formhandler extends Component {
constructor(props) {
super(props)
this.state = {
userName:""
}
}
changer=(event)=>{
this.setState(()=>{
userName : event.target.value
})
}
render()
{
return(
<div>
<label>UserName</label>
<input type="text" value={this.state.userName} onChange={this.changer}/>
</div>
)
}
}
export default Formhandler
You are getting the error because of invalid syntax.
Update changer function
changer = (event) => {
this.setState({ userName: event.target.value });
};
You need to return an object inside the setState function but you are not that's the source of issue(syntax error).
use a function inside setState when your new state value would depend on your previous state value, where the function passed inside the setState will receive previous state as argument
changer = (e) => {
this.setState((prevState) => ({
userName : e.target.value
})
);
}
pass an object to update the state, use this when it doesn't depend on your previous state value.
changer = (e) => {
this.setState({ userName: e.target.value });
};
import React from "react";
class Formhandler extends React.Component {
constructor(props) {
super(props);
this.state = {
userName: "",
};
}
changer(event) {
this.setState(() => ({
userName: event.target.value,
}));
}
render() {
return (
<div>
<label>UserName</label>
<input
type="text"
value={this.state.userName}
onChange={this.changer.bind(this)}
/>
</div>
);
}
}
export default Formhandler;
It will work, compare your version and this

Unable to change the value in the object

My objective is to change the value of the object to true or false while onchanging the checkbox.
Object contains:
{
id: '12497wewrf5144',
name: 'ABC',
isVisible: 'false'
}
Here is the code:
import React, { Component } from 'react'
class Demo extends Component {
constructor(props) {
super(props)
this.state = {
demo: {}
}
}
componentDidMount() {
axios
.get('/api/random')
.then(res => {
this.setState({ demo: res.data?.[0] })
})
.catch(error => {
console.log(error)
})
}
render() {
return (
<div>
<h1>{this.state.demo.name}</h1>
<input type="checkbox" value={this.state.demo.value} />
</div>
)
}
}
export default Demo
I don't know what to write in onchange method for checkbox to only change the value within the object.
Can anyone help me in this query?
<input
type="checkbox"
value={this.state.demo.value}
onChange={(event) => {
this.setState((prevState) => ({
...prevState,
demo: { ...prevState.demo, isVisible: event.target.checked }
}));
}}
/>
Given your state ends up looking like
this.state = {
demo: {
id: "12497wewrf5144",
name: "ABC",
isVisible: "false",
value: false
}
};
You can create a change handler as such
changeHandler = e => {
e.preventDefault();
const { checked } = e.target;
this.setState(prevState => ({
...prevState, // <-- spread existing state
demo: {
...prevState.demo, // <-- spread existing demo
value: checked, // <-- save the input's checked value
}
}))
}
Attach the changeHandler to the onChange event callback
<input
type="checkbox"
onChange={this.changeHandler}
value={this.state.demo.value}
/>
Ciao, you could use onClick event like this:
...
handleClick = (e, data) => {
const demo = { ...this.state.demo };
demo.isVisible = !demo.isVisible;
this.setState({ demo });
}
...
<input type="checkbox" value={this.state.demo.value} onClick={((e) => this.handleClick(e, data))}/>
...

Can't type in React input text field in Todo app

I am making a todo app in React.js but stuck in this part. I can not type in input field. Please help me.
import React, { Component } from 'react';
export default class AddItem extends Component {
state =
{
title: "",
done: false
}
changeTitle = (e) =>{
e.preventDefault();
this.setState = ({
title: e.target.value
});
}
addNewItem = (item) => {
item.preventDefault();
let newTask = {
title: this.state.title,
done: false
};
this.props.additem(newTask);
this.setState = ({
title: ""
});
}
render() {
return (
<div>
<form>
<input
type="text"
placeholder="add task name."
value={this.state.title}
onChange= {this.changeTitle}
/>
<button type = "button" onClick= {this.addNewItem} >submit</button>
</form>
</div>
)
}
}
this.setState is a function that is called with an object containing changes in state. The code you are using here is an assignment not a function call:
this.setState = ({
title: e.target.value // Wrong
});
Instead, call the setState function with the changes/updates in state. the changes are shallow merged and only title is updated here.
this.setState({title:e.target.value});
You will have a similar problem inside addNewItem.

React - controlled component issue

So I'm working on a controlled component for a unit converter - the problem is the output is a step behind what I want it to be (e.g if I type "100" it will give the value of 10kg in lbs, "1000" -> 100 etc.). I'm sure the fix is obvious but I can't see it myself - I'm still a React newbie!
import React, { Component } from 'react';
class SearchBar extends Component {
constructor(){
super();
this.state = {
kg: '',
lbs: '',
value: 'kgtolbs',
userInput: ''
}
this.convertKgToLbs.bind(this);
this.convertLbsToKg.bind(this);
this.handleOption.bind(this);
this.handleChange.bind(this);
}
handleOption(event){
const selectedValue = event.target.value;
this.setState({
value: selectedValue
});
}
handleChange(event){
this.setState({
userInput: event.target.value
})
if(this.state.value === 'kgtolbs'){
this.convertKgToLbs();
} else {
this.convertLbsToKg();
}
}
convertKgToLbs () {
const kg = this.state.userInput;
const lbsConversion = kg * 2.205;
this.setState({
lbs: lbsConversion.toFixed(1)
});
}
render(
){
return(
<div className="search-bar">
<input className="input" type="number" onChange={this.handleChange.bind(this)} />
<select onChange={this.handleOption.bind(this)}>
<option value="kgtolbs">Kg to Lbs</option>
<option value="lbstokg">Lbs to kg</option>
</select>
<p>{this.state.lbs} </p>
<p>{this.state.kg} </p>
</div>
);
}
}
export default SearchBar;
Any help appreciated - thanks !
setState is an asynchronous function. This means that in your handleChange function when you use this.state.value, the state has not actually been updated yet. setState has a callback handler to ensure do stuff after it has ran. In your case, you can do this:
handleChange(event){
this.setState({
userInput: event.target.value
}, function() {
if(this.state.value === 'kgtolbs'){
this.convertKgToLbs();
} else {
this.convertLbsToKg();
}
});
}

React Geosuggest doesn't update state

i'm trying to make a weather app, and using external component 'react-geosuggest'.
My problem is, when I update the input (SEE:onChange={this.onInputChange}), that function doesn't take my input, and don't change the state, i.e I get undefined.
What's interesting, i've set initialvalue to be New York, and on submit I get results, without changing input information, so problem lies in updating input information and passing it to function handleOnSubmit.
I've read docs about that component, but couldn't figure it out, it has same values as simple , but something doesn't work.
Thanks!
class SearchBar extends Component {
constructor() {
super()
this.state = {city: 'New York'};
}
onInputChange = (e) => {
this.setState({city: e.target.value});
}
handleOnSubmit = (e) => {
e.preventDefault();
this.props.fetchWeather(this.state.city);
this.setState({city: ''});
}
render () {
return (
<div>
<form onSubmit={this.handleOnSubmit}>
<Geosuggest
initialValue={this.state.city}
onChange={this.onInputChange}
types={['(cities)']}
/>
<button type="submit">Search</button>
</form>
</div>
</div>
);
}
}
Bind the event on the constructor, set the value attribute in the render and remove the setState to empty string that you are doing in the handleOnSubmit event. I am afraid this last one is what it makes not working when you change the input.
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = {city: 'New York'};
this.onInputChange = this.onInputChange.bind(this);
}
onInputChange = (city) => {
this.setState({city: city});
}
handleOnSubmit = (e) => {
e.preventDefault();
this.props.fetchWeather(this.state.city);
}
render () {
return (
<div>
<form onSubmit={this.handleOnSubmit}>
<Geosuggest
initialValue={this.state.city}
value={this.state.city}
onChange={this.onInputChange}
types={['(cities)']}
/>
<button type="submit">Search</button>
</form>
</div>
</div>
);
}
}
Use e.currentTarget.value instead. See this question for more on this.
Also try this:
onChange={this.onInputChange.bind(this)}
If you'd like to be more concise you can write it this way:
<Geosuggest
initialValue={this.state.city}
onChange={(e)=> this.setState({city: e.currentTarget.value})}
types={['(cities)']}
/>
You can also get the value of selected address using onSuggestSelect:
<Geosuggest
ref={el=>this._geoSuggest=el}
placeholder="Search for address"
onSuggestSelect={this.onSuggestSelect}
country='us'
/>
Then access the components like so:
onSuggestSelect(suggest) {
if (!suggest.gmaps) {
return;
}
const components = suggest.gmaps.address_components;
const address = {
street: this.findAddressComponent(components, 'street_number', 'short_name') + ' ' + this.findAddressComponent(components, 'route', 'short_name'),
city: this.findAddressComponent(components, 'locality', 'short_name'),
state: this.findAddressComponent(components, 'administrative_area_level_1', 'short_name'),
zip: this.findAddressComponent(components, 'postal_code', 'short_name'),
}
this.setState({
address
});
}
findAddressComponent(components, type, version) {
const address = components.find(function(component) {
return (component.types.indexOf(type) !== -1);
});
return address[version];
}

Resources