React - Update or Replace an Object with in the State object - reactjs

I have an State varaible with array of objects like this.
type State = {
Dp: ArrayDataProvider<string, Message>;
};
Inside Dp i will have data which will hold the data in the form of array like this.
[{
"id": 1,
"name": "January",
"abc": abc,
"xyz": xyz
}, {
"id": 2,
"name": "February",
"abc": abc,
"xyz": xyz
}]
I want to replace the object which is having id 2 with the different object and i want to have my object like this .
[{
"id": 1,
"name": "January",
"abc": abc,
"xyz": xyz
}, {
"id": 2,
"name": "New month",
"abc": 1234abc,
"xyz": someVlaue
}]
how to do it in efficient way with typescript in react.
I have done something like this but not working
const data = this.state.Dp?.data.slice();
const index = data.findIndex(currentItem => {
return currentItem.id === updateData[0].id;
});
data[index] = updateData;
this.state.Dp.data = data;
this.setState({ Dp: this.state.Dp });

I use map to do this:
const data = this.state.Dp?.data.map(currentItem => {
return currentItem.id === updatedItem.id ? updatedItem : currentItem;
})
map creates a new array with the items from the previous array, but it gives you an opportunity to make adjustments to the items in the new array as it iterates through them. In my example, I'm checking the id of the item to see if it's the one you want to update, and swapping in your updatedItem if the ids match.
I'm not sure about the TypeScript part, to be honest. I haven't worked with it yet.
Note - I'm not sure what form your updateData is in, so you might have to adjust that. It seems like you want it to be an object, but in one of your lines you're treating it like an array.

Use findIndex to find index of the object where id is equal 2, then replace new object to that place.
let tempArray = [...array];
const index = tempArray.findIndex((element) => element.id === 2);
tempArray[index] = {
id: 2,
name: "New month",
abc: "1234abc",
xyz: "someVlaue"
};
setArray(tempArray);

Related

react js lodash loop thru and change a field value

I am new at reactjs and lodash. I have an array of objects which each has many field properties. I want to change a name string value if the boolean property is true. I read thru some of the posts here, seem like .map will loop thru the array
const updatedList = this.props.oldList.map((record) => record.IsTrue === 1 ? `$({record.name} (Updated)` : record.name)
I ran the test and it did not worked at all. Instead of returning list of object with all its properities, I got the following
0: "Test1 (Updated)"
1: "Test2"
There is not object with field names and values. I was expecting the following
[
{name: "Test1 (Updated)", IsTrue: 1},
{name: "Test1", IsTrue: 0}
]
Any help with lodash is appreciated.
You can use spread syntax to return the other key and value and update the name-value where isTrue is 1.
const input = [{ name: "Test1", IsTrue: 1 }, { name: "Test1", IsTrue: 0 }],
output = input.map((record) => ({
...record,
name: record.IsTrue === 1 ? `${record.name} (Updated)` : record.name
}));
console.log(output);

Is there any way to update state by find Item and replace on a nested state?

I am building an order functionality of my modules in the component state on react
so the state object looks like that
"activity": {
"name": "rewwerwer",
"description": "werwerwerwerwer",
"modules": [
{
"name": "Text",
"order": 1,
"module_id": 1612,
},
{
"name": "Text2",
"order" 2,
"module_id": 1592,
}
]
}
handleSortUp = (moduleid ,newOrder) => {
const { modules } = this.state.activity;
const module = modules.find(element => element.module_id === moduleid);//Thios returns the correct object
this.setState({ activity: { ...this.state.activity.modules.find(element => element.module_id === moduleid), order: newOrder } });
}
I tried this but it updates the order field and object
but also removes all other objects from modules array :<
I like just to replace only the order field on each module by module id
and leave rest data there
the required response from the state that i need when the handleSortUp(1612,14); is fired
handleSortUp(1612,2);
{
"name": "rewwerwer",
"description": "werwerwerwerwer",
"modules": [
{
"name": "Text",
"order": 2,
"module_id": 1612,
},
{
"name": "Text2",
"order": 1,
"module_id": 1592,
}
]
}
I can do this on a simple array the question is how to update the State on react
Also the one way to change the order is answered fine but how also to change the field that had that order registered
So when we fire Change Item 1 order to 2 the Item 2 needs to take the Order 1
Thank you
Sure! This would be a great place to use the built-in .map method available for arrays. Consider the following example.
let array = [{order: 1, type: "food"}, {order: 2, type: "notfood"} ]
const newArray = array.map((item) => {
//CHECK TO SEE IF THIS IS THE ITEM WE WANT TO UPDATE
if(item.order == 1){
return {
...item,
newField: "newData"
}
} else {
return item
}
})
Output is:
[{order: 1, type: "food", newField: "newData"}
{order: 2, type: "notfood"}]
So yes you could totally update the module you're looking for without mutating the rest of your array. Then use your findings to update the component state using some good ol spread.
this.setState({
activity: {
...this.state.activity,
modules: newArray}
})
Of course they get all eliminated. Pay attention to what you wrote here:
this.setState({ activity: { ...this.state.activity.modules.find(element => element.module_id === moduleid), order: newOrder } });
What are you doing with that find? Let's see what Array.prototype.find() returns: https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Array/find
It returns an index, why would you insert an index into the state?
The answer partially came from yourfavoritedev.
As he said you can use the built-in Array.prototype.map() and do it like this:
handleSortUp = (moduleid ,newOrder) => {
const { modules } = this.state.activity;
const newModules = modules.map(module => module.module_id === moduleid ? { ...module, order: newOrder } : module)
this.setState({ activity: { ...this.state.activity, modules: newModules } });
}
This should work, let me know but I strongly advice to ask me or search on the web if you don't understand what is happening there (syntactically or semantically speaking).

How to remove the right element from array react?

I want to remove an element from my array when click on a specific row.
When I click on an element it does nothing or the last row gets deleted.
I tried to remove the element like this:
ondeleterow(e: any) {
const array = [...this.state.fields.columns]; // make a separate copy of the array
const index = array.indexOf(e.target.id);
if (index !== -1) {
array.splice(index, 1);
this.setState({ fields: { columns: array }});
}
}
My array/json object looks like this:
[ {index: 0, name: "person 1", age: 12},
{index: 1, name: "person 2", age: 19},
{index: 2, name: "person 3", age: 34},
]
My result should be when I click on a row with ID=1 the row with index: 1 gets deleted from my state array.
I can't give them an Id because when I submit the json structure then does not get accepted.
I feel like your Array.splice might be causing the issue here (because even though you created a new array, the objects in the array are still passed by reference).
I would recommend a completely different method of doing this operation which I've found to be far cleaner and robust.
First you have to add a unique id field to each row. (this is good practice in react anyway, instead of using index for keys).
ondeleterow(id: string) {
return (e: any) => {
const array = this.state.fields.column.filter(item => item.id != id)
this.setState({ fields: { columns: array }});
}
}
and when you're mapping over your rows, you can simply add the function to the onClick like this
<Row key={item.id} onClick={ondeleterow(item.id)} />
Never use splice in react especially with state. They directly mutate the data. Use non mutating operations like slice.
Your code should as follows
ondeleterow(e: any) {
const array = [...this.state.fields.columns]; // make a separate copy of the array
const index = array.indexOf(e.target.id);
if (index !== -1) {
array.splice(index, 1);
this.setState({ fields: {
columns: [ ...array.slice(0, index), ...array.slice(index + 1, array.length) ]
}});
}
}
You can use Array.filter. This will allow you to create a new array with only the items you want based on a certain criteria. In this case, you want an array with items that have a different ID that the one you want to remove. So it will look like this
// Actual processing
const filterByIndex = (arr, idx) => arr.filter(x => x.index !== idx);
// Your data
const json = [{
index: 0,
name: "person 1",
age: 12
},
{
index: 1,
name: "person 2",
age: 19
},
{
index: 2,
name: "person 3",
age: 34
},
];
// Printing the result
console.log(filterByIndex(json, 1));
In your React app
ondeleterow(e: any) {
const columns = this.state.fields.columns.filter(x => x.index !== e.target.id);
this.setState({ fields: { columns }});
}
Try this
onDeleteRow(e) {
const afterRemoval = this.setState.fields.columns.filter(item => item.index != e.target.id);
this.setState(prevState => ({ fields: { ...prevState.fields, columns: afterRemoval } }));
}
The other solution above sets the fields field directly, It may work but will cause problem if fields has some other attribute other than columns (those attributes will get removed)

Remove duplicate content from array

"name": [
{
"name": "test1"
},
{
"name": "test2"
},
{
"name": "test3"
},
{
"name": "test1"
},
]
I have the above created by nodejs. During array push, I would like to remove duplicated arrays from the list or only push the name array if the individual array does not exist.
I have tried below codes but it changes the array.
var new = [];
for (var i =0;i<name.length;i++){
new['name'] = name[i].name;
}
The easiest way is probably with Array.prototype.reduce. Something along these lines, given your data structure:
obj.name = Object.values(obj.name.reduce((accumulator, current) => {
if (!accumulator[current.name]) {
accumulator[current.name] = current
}
return accumulator
}, {}));
The reduce creates an object that has keys off the item name, which makes sure that you only have unique names. Then I use Object.values() to turn it back into a regular array of objects like in your data sample.
the solution can be using temp Set;
const tmpSet = new Set();
someObj.name.filter((o)=>{
const has = tmpSet.has(o.name);
tmp.add(o.name);
return has;
});
the filter function iterating over someObj.name field and filter it in place if you return "true". So you check if it exists in a tmp Set & add current value to Set to keep track of duplicates.
PS: new is a reserved word in js;
This should do it
const names = ['John', 'Paul', 'George', 'Ringo', 'John'];
let unique = [...new Set(names)];
console.log(unique); // 'John', 'Paul', 'George', 'Ringo'
https://wsvincent.com/javascript-remove-duplicates-array/

Typescript filter array of object by another array of strings

i stuck at my typescript filter function.
I have an array of objects:
[
{
"id": 12345,
"title": "Some title",
"complexity": [
{
"slug": "1" // my search term
"name": "easy"
}, {
"slug": "2" // my search term
"name": "middle"
},
{...}
And i have a array of strings with the allowed complexity:
public allowedComplexityArray:Array<string> = ["1"];
My Task: I only want to show objects with the allowed complexity of "1".
But somehow my function dont work and i dont know why:
allowedMeals = meals.filter(meal => {
return meal.complexity.every(complexityObj => that.allowedComplexityArray.indexOf(complexityObj.slug) > -1)
});
try:
let allowedMeals = data.filter(meal => {
return meal.complexity.findIndex(complexityObj =>
allowedComplexityArray.findIndex(m => m == complexityObj.slug) > -1) > -1
});
I'm using findIndex instead of filter in the return clause so it does not need to scan the whole array every time.

Resources