How to setState from function parameter in React [duplicate] - reactjs

This question already has answers here:
React this.setState is not a function
(16 answers)
Closed 3 years ago.
I am passing the name and value to handleChange function from child component.
Now I want to set the state to the value that matches the provided name.
But I do not know how to set it.
I tried this way(but it gives error - 'this.setState is not a function') :
class ParentComponent extends Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
this.state = {
loanAmount: 348600.48,
numberOfYears: 70,
}
handleChange(name, value) {
this.setState({ name: value },() => {
this.financeCalcualte();
});
}
The code of the child component is:
onChange = (event) => {
const {name, rawValue} = event.target;
this.props.handleChange(name, rawValue)
}
What is the correct syntax to set it?

In order to use this in a callback function, as told in the comments you have to bind it in the constructor or use an arrow function.
Also, since your name is a variable, you can't update your state like:
this.setState({ name: value }
because this creates a name property in your state, does not update the state variable which has the name as your incoming variable. So, you should use a computed property.
handleChange = (name, value) =>
this.setState({ [name]: value }, () => this.financeCalcualte());

It seems like you are looking for computed property name
handleChange(name, value) {
this.setState({ [name]: value },() => {
this.financeCalcualte();
});
}

If you have this function in a Class based component then you can update your current function to an arrow function like below.
handleChange = (name, value) => {
this.setState({ name: value },() => {
this.financeCalcualte();
});
}
The thing is you are accessing this without a context being given.
Another way can be you bind this to the function. Below is the example to do it the other way inside your constructor.
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
// Other code ....
}
EDIT
Also as mentioned in other answer and comments you have to use computed property name, you can not just use a variable name directly and set it to another variable.
this.setState({[name]:value})

Related

React updating props from state

I have a form inside a list.
The list passes a object with a array of topics (another object) on props to the child form, and when I change the values on the state the props values are changed also.
I would like to maintain props in case the user cancels the changes.
constructor(props: IMinuteProps) {
super(props);
this.state = {
meeting: this.props.meeting,
EditingThemeDeliberation: undefined
};
}
After Changing the field event:
(EditingThemeDeliberation is the topic being changed)
private UpdateDeliberation(event) {
let { Reunion, EditingThemeDeliberation} = this.state;
EditingThemeDeliberation.Deliberation = event.target.value;
Reunion.Themes.splice(Reunion.Themes.findIndex(i => i.Id ===
this.state.EditingThemeDeliberation.Id), 1,EditingThemeDeliberation);
// Previous command changes both props and state
this.setState({ EditingThemeDeliberation: undefined, Reunion: Reunion
});
}

React Binding and Populating an Object

I have a React Component which maintains a Local State as shown below:
this.state = {
user : {}
}
I have 2 textboxes on the screen where I can enter name and age. I am sending the values from the textboxes and populating the user object inside the state as shown below:
onTextBoxChange = (e) => {
// this.user is a property on the Component declared inside the // constructor
this.user[e.target.name] = e.target.value
this.setState({
user : this.user
})
}
Is there a better way of populating the state with the user object which consists of name and age.
There is no need to create an extra variable (let user =...) or a member variable (this.user).
Just overwrite previous values using spread syntax.
onTextBoxChange = e => {
this.setState({
user: {
...this.state.user,
[e.target.name]: e.target.value
}
});
};
Here is the fully working version on CodeSandBox.
You can achieve the same by following three different ways:
1) There's no need to creating an this.user property, instead to can achieve the same by using a local variable. So, the function can be changed to:
onTextBoxChange = (e) => {
let user = this.state.user;
user[e.target.name] = e.target.value;
this.setState({
user: this.user
})
}
2) If you're not using user state in input text boxes for value, then you can simply use this.user property instead of using a state, which will cause re-rendering.
You can then use the this.user when the form submitted, for example.
3) Again, If you're not using user state in input text boxes for value, then you can also use React refs and get the value directly from the element when the form is submitted, for example.
You might try this in a parent component:
onTextBoxChange = (field, value) => {
this.setState({user:{
...this.state.user,
[field]: value
}
});
}
and then this in the child component:
onNameChange = (e) => {
this.props.onChange('name', e.target.value)
}
onAgeChange = (e) => {
this.props.onChange('age', e.target.value)
}

ReactJS change value of nested state

I have a form in which inputs have an initial value (which is different for each input). I set the value by saving the data in a state array, like so:
function createData(header, content) {
id += 1;
return {header, content, id};
}
class ExampleForm extends React.Component {
constructor(props) {
super(props);
this.state = {
data : [
createData( Header1, Content1),
createData( Header2, Content2),
createData( Header3, Content3),
]
}
Once the user startes typing something into the input field, I need to change the value of the state in in question in the corresponding array, however, I'm having trouble correctly targeting said state.
This is what I'm currently doing:
handleInputChange = (value, target) => {
const selectedArray = {...this.state.data[target]};
selArray.header = value;
this.setState(selArray);
};
}
(Note: value is the new value, target is the index)
However, it doesn't work because when I console.log() the new value, it still returns the old value.
I also read several other questions on here (with the help of with I wrote the code for what I'm doing right now in the function that changes the value), however, that did not work.
Other questions I read include React: Update nested state? , however, I could not figure out where they got getPersonsData() from, for instance. Does anyone know what I'm doing wrong in my current code? How do I fix it?
Update the state like this:
handleInputChange = (value, target) => {
const data = [...this.state.data];
data[target].header = value;
this.setState({ data });
};
To check the updated state value, use callback method, like this:
handleInputChange = (value, target) => {
const data = [...this.state.data];
data[target].header = value;
this.setState(
{ data },
() => console.log('updated state', this.state.data)
);
};
For more details about asyn behaviour of setState check this answer: Why calling setState method doesn't mutate the state immediately?

Is Initializing state with props object causes mutation?

In my React application, one of the components needs state initialization from props.
Class ComponentA extends React.Component{
constructor(props){
this.state = {
objectA: props.objectA
}
}
someOnclickFunction(e){
let updatedObjA = this.state.objectA;
updatedObjA.value = e.target.value;
this.setState({
objectA: updatedObjA
})
}
}
In the above code snippet, props.objectA reference is copied to state. So, Am I mutating the props indirectly by updating the state?
Or setState() function will clone the object and keep new reference for the objectA?
class ComponentA extends React.Component {
constructor(props) {
super(props);
// state is null at this point, so you can't do the below.
// this.state.objectA = props.objectA
// instead, initialize the state like this:
this.state = {
objectA: props.objectA,
};
}
someOnclickFunction(e) {
// you can't set "objectA.value" like the following
// this.setState({
// objectA.value: e.target.value
// });
// you need to create a new object with your property changed, like this:
this.setState({
objectA: Object.assign({}, this.state.objectA, { value: e.target.value }),
})
}
}
This is a mistake that many beginners at react make. You can't simply update sub-properties of an object without consequences.. The following would also be wrong:
someOnclickFunction(e) {
var tmp = this.state.objectA;
// WRONG: don't do this either, you're modifying the state by doing this.
tmp.value = e.target.value;
this.setState({
objectA: tmp,
});
}
To elaborate on the correct way to do this using Object.assign.. this function takes all the parameters and merges them into the first element. So by providing a new object as the first parameter, you've created a copy of your first object with your new property.
Object.assign({}) // = {}
Object.assign({}, objectA) // = copy of objectA
Object.assign({}, objectA, { value: "newValue" }) // = copy of objectA with 'value' = 'newValue'.
Note: Object.assign() is a shallow clone, not a deep clone.

Why does it display only the last value of the array, and not the whole?

Why does it display only the last value of the array, and not the whole?.
When you update the value in the database, When you update the value in the database, it outputs all
constructor(props) {
super(props);
this.name = this.props.name;
this.state = {[this.name] : []};
}
componentDidMount() {
let cardQuantity =
firebase.database().ref("Users").child(this.name);
cardQuantity.on('value',snap => {
snap.forEach((childSnapshot)=> {
let card = {text: childSnapshot.val(), id: childSnapshot.key};
this.setState({[this.name] :[card].concat(this.state[this.name])});
});
});
}
render(){
return (
this.state[this.name].map( card => <h2 key={card.id}>{card.text}</h2>)
);
}
setState() is async so you have to use callback form of setState like below:
this.setState(prevState => ({
[this.name]: [card].concat(prevState[this.name])
}));
Demo: https://codesandbox.io/s/zrq0xxq2px
It shows 2 versions based on your code:
fixed version that is using callback form of setState and displaying the whole list
unfixed version based on your code that is showing only the last element of an array
From the official React's documentation:
If the next state depends on the previous state, we recommend using
the updater function form, instead...

Resources