I have an object in the state ,
this.state = {
selectedValue: {}
}
Now,Here I am adding a property to this by object in the following way
if (e.currentTarget.checked) {
this.setState({
selectedType: {
...this.state.selectedType,
[resumeId]: type
}
})
Now, In else part I have to remove the property with the matching resumeId.
Or Do I need to create an array of objects ? I am kind of confused here.
Can any one help me with this ?
The best way to do this is add a prefix to your resumId:
if (e.currentTarget.checked) {
this.setState({
selectedType: {
...this.state.selectedType,
[`resume-${resumeId}`]: type
}
})
Now, you have a way to identify your resumeId. Then loop through your selectedType state and remove resumeId. You can do it as the following:
let selectedType = this.state.selectedType;
for (let key in selectedType) {
if (key.indexOf('resume') !== -1) {
delete selectedType[key]
}
}
this.setState({selectedType})
if (e.currentTarget.checked) {
this.setState({
selectedType: {
...this.state.selectedType,
[resumeId]: type
}
}) else {
const selectedType = {
...this.state.selectedType
}
delete selectedType[resumeId];
this.setState({
selectedType
});
}
You can delete the resumeId from the object iself.
Use Object destructuring to acheive this cleanly:
if (e.currentTarget.checked) {
this.setState({
selectedType: {
...this.state.selectedType,
[resumeId]: type
}
})
} else {
// Destructure the resumeId and rest properties
const { resumeId, ...rest} = this.setState.selectedType;
// Only assign the rest properties now
this.setState({ selectedType: ...rest });
}
Update:
To check if all values are same:
const data = { "a": "11", "b": "11", "c":"12", "d" : "11" };
const objectValues = Object.values(data);
// Check first value with every value
const isEveryValueSame = objectValues.every(x => x === objectValues[0]);
console.log(isEveryValueSame);
Related
I want to update object key name on setState. I have this object:
let obj = {
sponsorship: {
a: {
task: "x",
todo: "y"
},
b: {
task: "x1",
todo: "y2"
}
}
};
setForm(obj);
Now want to rename one of object key name:
setForm({
...form,
sponsorship: {
...form.sponsorship,
[newName]: { ...form.sponsorship[oldName] }
}
});
I tried this but it will add new object not replace. also tried this:
setForm({
...form,
sponsorship: {
[newName]: { ...form.sponsorship[oldName] }
}
});
But this will remove all prev object. but I need to for example rename a key to c
Demo
If you don't want to delete a property and you are searching for an alternative way to do it, you can filter the sponsorship properties and return a new object without the oldValue
setForm({
...form,
sponsorship: {
...Object.fromEntries(
Object.entries(form.sponsorship)
.filter(([key]) => oldName !== key)
),
[newName]: { ...form.sponsorship[oldName] }
}
});
I have an object to collect data to send to an API:
apiData: {
colors: [],
years: [],
// ..
}
Many of the children of this apiData are arrays like colors and years, I call these 'subgroups'. A user can select a multitude of subgroups with checkboxes that trigger:
handleCheckboxColorChange(value, isChecked) {
let newApiData = '';
this.setState( (prevState) => {
if (isChecked === true) {
newApiData = {...prevState.apiData, colors: [...prevState.apiData.colors, value]}
} else {
newApiData = {...prevState.apiData, colors: [...prevState.apiData.colors.filter(item => item !== value)]
}
}
return {apiData: newApiData}
}, () => this.props.handleApiCall(this.state.apiData))
}
I use a similar function for the other 'subgroups'. For years, all that changes in the function is colors to years. So I wish to create a more general function that can take a 'subgroup' as argument to target the right array in my object. I tried to pass a third variable (a string) subGroup like so:
handleCheckboxChange(value, isChecked, subGroup) {
// ..
newApiData = {...prevState.apiData, subGroup: [...prevState.apiData.subGroup, value]}
This does not work (I guess because it is now looking for the child 'subgroup' in my object). How can I make this work?
Use bracket notation :
handleCheckboxChange(value, isChecked, subGroup) {
// ..
newApiData = {...prevState.apiData, [subGroup]: [...prevState.apiData[subGroup], value]}
To make it a bit prettier, you can use this:
handleCheckboxColorChange(value, isChecked, subGroup) {
this.setState((prevState) => {
const newState = { ...prevState }
newState[subGroup] = isChecked ? [ ...newState[subGroup], value ] : newState[subGroup].filter(item => item !== value)
return newState
}, () => this.props.handleApiCall(this.state.apiData))
}
I have this type of state in my app
state = {
abc: true,
array: [
{ id: 12345, done: false },
{ id: 10203, done: false },
{ id: 54321, done: false }
]
};
I am looking for a solution to the following problem: I need to change done property accordingly to passed id like in the following function when something like this handle(12345) is passed as an argument to handle function :
handle = id => {
this.state.array.map(e => {
if (e.key === id) {
this.setState({array: [
{ id: id, done: true },
{ id: 10203, done: false },
{ id: 54321, done: false }
]})
}
});
};
In simple words I need to change just one object in array based on provided id.
Thanks for any help or tips!
I'd write the handle method as:
handle = id => {
this.setState(prevState => {
const { array } = prevState;
return {
array: [
...array.filter(o => o.id !== id),
{id, done: true}
]
};
});
};
The idea here is that, remove the matching id from old state, and then add a new object to the array with id and done property as {id, done: true}.
Once you are allowed to restructure state to be hashmap instead of array:
state = {
abc: true,
array: {
12345: { done: false },
10203: { done: false },
54321: { done: false }
]
};
then you will be able to use power of spread operator:
let id = 12345;
this.setState({
array: {
...this.state.array,
[id]: {
...this.state.array[id],
done: true
}
}
});
Otherwise using array.map() seems to be the only option
You can use this Redux pattern to return a new array with the element in question being changed, while keeping your array immutable:
handle = id => {
const updatedArray = this.state.array.map(e => {
if (e.key === id) {
return { id: id, done: true };
}
else {
return e;
}
});
this.setState({array: updatedArray});
};
This keeps your data structures immutable while changing only what you need to change.
var newArray = this.state.array;
for(var i = 0; i < newArray.length; i++){
if(newArray[i].id === 12345) {
newArray[i].done = true;
}
}
this.setState({array: newArray});
By creating the newArray here you will be avoiding directly touching the state element, so you can change anything you want inside it afterwards you can set the state.
I am working on an online class, for which we have to build a list tracker application using react. I have had issues when trying to set the state of one of my classes. In this state I have a variable which is equal to an object. I am attempting to variably set both the name and value of this object, however I was uncertain on how to set the name variably.
let name = this.props.idName;
this.setState((prevState) => {
return {
newItem: { name: item}
};
}, () => {
this.props.addItem(this.state)
});
As you can see, I try to set the key in this object equal to the variable name, however this just sets it to the value of name rather than the value of the the name variable.
You can try this. Just enclose the name in square brackets. More on this https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names.
let name = this.props.idName;
this.setState((prevState) => {
return {
newItem: { [name]: item}
};
}, () => {
this.props.addItem(this.state)
});
var k = "key";
var obj = {[k]: "VALUE"}
console.log(obj);
You can regard objects as dictionaries:
$ node
> let name = 'Nyan'
undefined
> let omg = { newItem: {} }
undefined
> omg
{ newItem: {} }
> omg['newItem'][name] = 'item' // note the quotes in this statement
'item'
> omg
{ newItem: { Nyan: 'item' } }
In my case, I'm using React.js and I would like to dynamically update the values in the deployOptions object.
For example -
initial state looks like:
getInitialState() {
return {
deployOptions: {
config: null,
action: 'deploy',
env: 'qa'
}
}
}
Obviously this is not correct - but this is what I'm trying to achieve
configOptionChange(option) {
// option -> { key: 'env', value: 'prod' }
this.setState({
[deployOptions.option.key]: option.value
});
}
so that my state would then be
{
deployOptions: {
config: null,
action: 'deploy',
env: 'prod' // only this changes
}
}
It's not especially pretty, but I think this is the best you can do with ES6:
configOptionChange({ key, value }) {
this.setState({
...this.state,
deployOptions: {
...this.state.deployOptions,
[key]: value
}
});
}
It's basically equivalent to your own Object.assign solution but using the ES6 spread (...) operator (and argument destructuring for good measure).
Here's a second option that isn't as clever but feels a little cleaner to me:
configOptionChange({ key, value }) {
const { deployOptions: prevDeployOptions } = this.state;
const deployOptions = { ...prevDeployOptions, [key]: value };
this.setState({ ...this.state, deployOptions });
}
Just like these are nested objects, you can nest ES6 Computed Property Name like this:
[yourNestedObject]: {...yourNestedObject, [nestedObjectProperty]: value}
Here is an example function that will update an object's properties and the properties of nested objects. Where prop is the property to change, value is the value to assign, and propObj is the name of your nested object. I used useState hook for this.
const [obj, setObj] = useState({
prop1: '',
prop2: '',
nestedObj: {
prop1: '',
prop2: ''
}
});
const updateObj = (prop, value, propObj=false) => {
if (propObj) {
setObj({...obj, [propObj]: {...obj[propObj], [prop]: value}})
} else {
setObj({...obj, [prop]: value})
}
}
I think this might do the trick - but if anyone has a better solution?
configOptionChange(option) {
this.setState({
deployOptions: Object.assign({}, this.state.deployOptions, {[option.key]: option.val})
});
}
I'm using reduce to update the state of a component from a passed string of path properties:
handleChangeNested(event) {
const target = event.target; //an <input /> tag
let newState = { ...this.state };
let valuePath = target.name.split('.'); //the input's name is the the keys of the state object like 'group1.input1'
// Move down in the state object until we get to the 'bottom' property and change its value
// If the object does not have the properties we create them on the fly
valuePath.reduce((acc, key, index, path) => {
if (index === path.length - 1) {
acc[key] = target.value;
}
acc[key] = acc[key] || {};
return acc[key];
}, newState);
this.setState(newState);
}
The best solution I know would be to use "immutable" library.
configOptionChange(option) {
// option -> { key: 'env', value: 'prod' }
this.setState(state => setIn(state, ['deployOptions', option.key], option.value));
}