react-native: How to setState() dynamic state in react-native? - reactjs

I can create dynamic state like this example:
constructor(props) {
super(props);
this.state = {};
}
create state with this method:
func(name){
this.state[name];
}
and setState with this:
func2(name,value){
this.setState({[name]:value});
}
so with
this.func('color');
this.func('size');
I have this.func.color and this.func.size. right?
It works.
But I want something like this. I want create all new dynamic state in 'names' state.
constructor(props) {
super(props);
this.state = {names:[]};
}
names is a normal state.
func(name){
this.state.names[name];
}
func2(name,value){
this.setState({names:{[name]:value}:});
}
I call this functions:
func('color');
func('size');
func2('color','red');
func2('size','larg');
I expect with console.log(this.state.names) this:
{color:'red',size:'larg'}
But I get only {size:'larg'} (second function)
what is my wrong?

You're overwriting the value of names when you call this.setState again.
You're effectively doing:
this.setState({ names: { color: 'red' }});
this.setState({ names: { size: 'large' }});
Consider using Object.assign() in func2 to make sure you're not replacing the object you're trying to add properties to.
func2(name,value) {
this.setState({
names: Object.assign(this.state.names, {[name]: value})
});
}

Related

How to update React component?

I have a child object (element of list) which is rendered inside(?) the parent one. The component has the following properties (from JSON):
contract
{
id,
name,
}
But I need to add another one additional property which is filled in after an HTTP request with an external function to the API (for example, uuid) using one of the existing properties of an object.
My current React code looks the following way (only child component is provided):
class Contract extends Component {
constructor(props){
super(props);
this.state = {data: this.props.contract};
getUuidByName(this.state.data.name).then(val => {
this.state.data.uuid = val;
});
}
componentDidUpdate(){ }
render() {
return <tr>
<td>{this.state.data.id}</td>
<td>{this.state.data.name}</td>
<td>{this.state.data.uuid}</td>
</tr>
}
}
Everything rendered good except an additional property: uuid. Of course I do something wrong or don't do some important thing, but I have no idea what to do.
You are mutating state in the constructor. Never mutate state directly. If you are needing to set/initialize some state after it's been constructed, or mounted, then you should use the componentDidMount lifecycle method. Ensure you enqueue the state update via the this.setState method.
class Contract extends Component {
constructor(props){
super(props);
this.state = {
data: props.contract,
};
}
componentDidMount() {
getUuidByName(this.state.data.name).then(val => {
this.setState(prevState => ({
data: {
...prevState.data,
uuid: val,
},
}));
});
}
componentDidUpdate(){ }
render() {
return (
<tr>
<td>{this.state.data.id}</td>
<td>{this.state.data.name}</td>
<td>{this.state.data.uuid}</td>
</tr>
);
}
}
Do not modify state directly.
Because you're directly modifying the state, React isn't triggering a re-render.
Try the following in your constructor instead:
constructor(props){
super(props);
this.state = {data: this.props.contract};
getUuidByName(this.state.data.name).then(val => {
this.setState({
data: {
...this.state.data,
uuid: val
}
});
});
}

Empty nested array when initializing state object

I've the following state initialised in a react app:
constructor(props) {
super(props);
this.state = {
meetings: [],
}
}
I need this.state.meetings to contain { Meetings: [] } until it is populated based on user action. How can i set this before the page renders?
The reason is that i have map functions running on this.state.meetings.Meetings and so i get an undefined error, which makes sense if the default is []. Rather than handle this in the code i wonder if i can just set Meetings: [] as a default value?
I would highly discourage you to store it as a nested structure. Keep it as flat as possible. So instead of directly setting the nested field Meetings inside state, just push or replace the data received from the api in the meetings field.
yourApiCall.then((response) => { // some pseudo code
this.setState({ meetings: response.Meetings });
});
Yeah, it's relatively simple, simply do
constructor(props) {
super(props);
this.state = {
meetings: {
Meetings: []
},
}
}
p.s. it also isn't good practice to have your object parent name be the same as a child :)
You can either do this.state = { meetings: { Meetings: [] } } because javascript is type free, this.state.mettings can assign to a [] later on.
Or a safer way:
// if meetings.Meetings is undefined, use empty array
const Meetings = this.state.meetings.Meetings || [].
//use Meetings to do stuff

React Native, construct initial state values from a object or array

Is it possible to create states in the constructor passed to that component from an array or object.
Here is what is to be achieved:
constructor(props) {
super(props);
this.state= {
Object.keys(this.props.data).map((key, i) => {
[key]: 'boo',
})
}
}
but it returns a syntax error.
The idea is that the data within this.props.data creates a series of states. The data passed to this.props.data is not known by the component in advance but is passed to it as a prop when the component is used.
You could directly declare this.state with return array of map
updated
constructor(props) {
super(props);
this.mapData = Object.keys(this.props.data).map((key, i) =>({[key]: 'boo'}))
this.state = this.pre_state ? Object.assign({}, ...this.pre_state) : {};
}

Can I use state value again in state?

i want to use index value for index_child, but this.state is undefined
state ={
index:0,
index_child:this.state.index
}
This code also fails.
state ={
index:0,
index_child:this.index
}
I dont know why you want to do that, but you can try something like this.
this.state = {
index:10,
get index_child () {
return this.index
}
};
console.log(state);

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.

Resources