Adding object in Array in nested object with setState - reactjs

I'd like to know how to add an object in datasets,
I'm trying to add an object in array with using setState,
but It doesn't work at all .
my code is like this :
const [DataContext, setDataContext] = useState([
{
labels: defaultLabels,
datasets: [
{
label: "dataSetting",
data: defaultDatas,
backgroundColor: defaultBackgroundColor,
},
],
},
{
labels: defaultLabels,
datasets: [
{
label: "dataSetting",
data: defaultDatas,
backgroundColor: defaultBackgroundColor,
},
],
},
{
labels: defaultLabels,
datasets: [
{
label: "dataSetting",
data: defaultDatas,
backgroundColor: defaultBackgroundColor,
},
],
},
const addAxis = index => {
let addAxis = [...DataContext];
addAxis[index].datasets.push({ label: "", data: "", background: "" });
setDataContext(addAxis);
};

You need a deep copy to update the state:
const addAxis = index => {
setDataContext(dataContext => dataContext.map((data, idx) => {
return idx === index ? {
...data,
datasets: [...data.datasets, { label: "", data: "", background: "" }]
} : data
})
};

You need to deep copy DataContext.
const _copy = (value) => {
let object;
if (Array.isArray(value)) {
object = [];
value.forEach((item, index) => {
if (typeof value[index] === 'object') {
object[index] = _copy(value[index]);
} else {
object[index] = value[index];
}
});
} else {
object = {};
for (let key in value) {
if (typeof value[key] === 'object') {
object[key] = _copy(value[key]);
} else {
object[key] = value[key];
}
}
}
return object;
};
const addAxis = index => {
let addAxis = _copy(DataContext);
addAxis[index].datasets.push({ label: "", data: "", background: "" });
setDataContext(addAxis);
};

Related

REACT: Updating nested state

I have two sets of data. Both are saved in a states.I want to update the rowsData inside the data1 state based on the values in data2 state. The "row" value in the data2 object refers to the "id" of rowsData in the data1 state and columns in the data2 refers to any data beside id in the rowsData object in data1. I want to pick "row" and "column" from data2 and cahnge the respective data inside rowsData in data1.
let tableData = {
columnsDef: [
{ title: "id",field: "id",className: "header-style" },
{ title: "First_name", field: "First_name", className: "header-style" },
{ title: "Last_name", field: "Last_name", className: "header-style" },
{ title: "Email", field: "Email", className: "header-style" },
],
rowsData:[
{ id: "1", First_name: "Donald", Last_name: "OConnell", Email: "DOCONNEL" },
{ id: "2", First_name: "Douglas", Last_name: "Grant", Email: "DGRANT" },
{ id: "3", First_name: "Jennifer", Last_name: "Whalen", Email: "JWHALEN" },
{ id: "4", First_name: "Michael", Last_name: "Hartstein", Email: "MHARTSTE" },
{ id: "5", First_name: "Pat", Last_name: "Fay", Email: "PFAY" },
{ id: "6", First_name: "Susan", Last_name: "Mavris", Email: "SMAVRIS" },
{ id: "7", First_name: "Hermann", Last_name: "Baer", Email: "HBAER" }
],
file: [
{ file: { path: "dummy_data_3 .csv"}}
],
}
let updatedTableData = [
{ "row": 2, "column": "Email", "oldValue": "DGRANT", "newValue": "DGRANT UPDATED" },
{ "row": 6, "column": "First_name", "oldValue": "Susan", "newValue": "SUSAN UPDATED" },
{ "row": 4, "column": "Last_name", "oldValue": "Hartstein", "newValue": "Hartstein UPDATED" }
]
const [data1, setData1] = useState(tableData)
const [data2, setData2] = useState(updatedTableData)
Here is the codesandbox link for the issue.
https://codesandbox.io/s/reverent-firefly-r87huj?file=/src/App.js
You can follow these steps for updating data1 from handleAppyChanges function:
Create a copy of rowsData:
const td = [...data1.rowsData];
Iterate over data2 and find related item, then update its related column:
data2.forEach((item) => {
let row = data1.rowsData.find((r) => r.id === item.row);
if (row) {
let index = data1.rowsData.findIndex((v) => v === row);
row[item.column] = item.newValue;
td[index] = row;
}
});
Update table data via state:
const newData = {
file: data1.file,
rowsData: td,
columnDef: data1.columnsDef
};
setData1(newData);
Here's the full function:
const handleAppyChanges = () => {
const td = [...data1.rowsData];
data2.forEach((item) => {
let row = data1.rowsData.find((r) => r.id === item.row);
if (row) {
let index = data1.rowsData.findIndex((v) => v === row);
row[item.column] = item.newValue;
td[index] = row;
}
});
const newData = {
file: data1.file,
rowsData: td,
columnDef: data1.columnsDef
};
setData1(newData);
console.log("Updated Data 1: ", td);
};
You can access the full code via codesandbox:
Apply into onChange and check it.
const handleAppyChanges = () => {
data2.map((item) => {
data1.rowsData.map((data) => {
//match both id and row
if (data.id == item.row) {
//check column is there or not
let column = data.hasOwnProperty(item.column);
if (column) {
//if yes then change the value
data[item.column] = item.newValue;
}
}
});
});
setData1({ ...data1 });
};

Why can't I push in <option> when I get the 'response.data'?

Why can't I push in my <option> when I get the response.data?
type State = {
companyManagerMap: null | Map<string, string[]>
}
useEffect(() => {
AdminListManager()
.then((response) => {
const { data } = response.data
console.log( { data });
setState((s) => ({
...s,
companyManagerMap: new Map(
Object.keys(data).map((key) => [key, data[key]])
),
}))
})
.catch(showUnexpectedError)
}, [showUnexpectedError])
data format
{"total":2,"data":[{"id":1,"name":"newspeed","contains_fields":[{"id":1,"name":"Official"}]},{"id":2,"name":"YAMAHA","contains_fields":[{"id":3,"name":"US"}]}]}
You are using your .map and Object.keys wrong
Look here at where you iterate over your Object keys properly :)
const data = {
total: 2,
data: [
{ id: 1, name: 'newspeed', contains_fields: [{ id: 1, name: 'Official' }] },
{ id: 2, name: 'YAMAHA', contains_fields: [{ id: 3, name: 'US' }] },
],
};
//now iterate over it properly
data.data.map((item) => {
Object.keys(item).map((key) => {
console.log(item[key]);
});
});
console.log will return this output
1
newspeed
[ { id: 1, name: 'Official' } ]
2
YAMAHA
[ { id: 3, name: 'US' } ]
I'm guessing you want to add the new data from your res.data to a state
So you can do something like this:
const fetchData = async () => {
try {
const res = await AdminListManager()
//do data manipulation over objects and set new state
} catch (error) {
showUnexpectedError()
}
}
useEffect(()=> {
fetchData()
}, [showUnexpectedError])

Remove object in array

I have a array object and a array.
const arr1=[
{ name: "viet" },
{ name: "hai" },
{ name: "han" }
]
const arr2= ["viet", "hai"];
How can i compare and set arr like:
arr = [{name: "han"}]
Try this code :D
const arr1=[
{ name: "viet" },
{ name: "hai" },
{ name: "han" }
]
const arr2= ["viet", "hai"];
const result = arr1.filter(item => !arr2.includes(item.name))
console.log(result) // [{name: "han"}]
const arr1=[
{ name: "viet" },
{ name: "hai" },
{ name: "han" }
]
const arr2= ["viet", "hai"];
let res = arr1.filter(function (n) {
return !this.has(n.name);
}, new Set(arr2));
console.log(res);

How to map the following to react state as expected result

Json data as follows
const data=
{
"id":1,
"title":"Test title",
"results":[
{
"rowId":1,
"records":[
{
"attribute":"Id",
"value":"id1"
},
{
"attribute":"title",
"value":"Perform data"
}
]
},
{
"rowId":2,
"records":[
{
"attribute":"Id",
"value":"id2"
},
{
"attribute":"title",
"value":"Test data"
}
]
}
]
}
Expected:
0:Id: "id1",
title:"Perform data"
1:Id: "id2",
title:"Test data"
Map the data results to new objects accessing the records array to be reduced to an object with correct mapped keys.
data.results.map(({ records }) =>
records.reduce(
(obj, { attribute, value }) => ({
...obj,
[attribute]: value
}),
{}
)
);
const data = {
id: 1,
title: "Test title",
results: [
{
rowId: 1,
records: [
{
attribute: "Id",
value: "id1"
},
{
attribute: "title",
value: "Perform data"
}
]
},
{
rowId: 2,
records: [
{
attribute: "Id",
value: "id2"
},
{
attribute: "title",
value: "Test data"
}
]
}
]
};
const result = data.results.map(({ records }) =>
records.reduce(
(obj, { attribute, value }) => ({
...obj,
[attribute]: value
}),
{}
)
);
console.log(result);

How to update existing object

I'm trying to update current object within an array with new property using state hooks. The array with object looks like this:
const myData = [
{
dataLabels: [
{
align: 'left'
}
],
name: 'my data',
data: [
{
y: 1,
name: 'Daryl'
},
{
y: 2,
name: 'Negan'
}
]
}
];
and I wan't to add color property to data objects inside useState hook. This is what I've tried so far:
const [ newMyData ] = useState({
...myData,
0: {
...myData[0],
data: myData[0].data.map((item, index) => ({ ...item, color: getChartColors()[index] }))
},
});
but the problem is that newMyData is now turned into an object instead of keep being an array. What am I doing wrong and how should I solve my problem? Thanks in advance
You are passing an object as the initial state:
const [ newMyData ] = useState([ /* <--- use '[' not '{' */
...myData,
0: {
...myData[0],
data: myData[0].data.map((item, index) => ({ ...item, color: getChartColors()[index] }))
},
] /* <--- same here - use ']' not '}' */ );
UPDATE:
Based on what you asked in the comments:
const myData = [
{
dataLabels: [
{
align: 'left'
}
],
name: 'my data',
data: [
{
y: 1,
name: 'Daryl'
},
{
y: 2,
name: 'Negan'
}
]
}
];
const myObject = myData[0];
const nextObject = {
...myObject,
data: myObject.data.map((item, index) => ({ ...item, color: getChartColors()[index] }))
}
const [myData, setMyData] = useState([ nextObject ]); /* If you still want this to be an array */
/* OR */
const [myData, setMyData] = useState( nextObject ); /* If you want it to be an object instead */
Hi you can follow this example to include new property in array using useState hooks.
import React, {useState} from "react";
export default function UseStateExample() {
const [myData, setMyData] = useState([
{
dataLabels: [
{align: 'left'}
],
name: 'my data',
data: [
{y: 1, name: 'Daryl'},
{y: 2, name: 'Negan'}
]
}
]);
function getChartColors() {
return ["red", "green", "blue"]
}
function clickHandler(event) {
let items = [];
myData[0].data.map((item, index) => {
item.color = getChartColors()[index];
items.push(item);
});
setMyData([
...myData
]);
console.log(myData)
}
return (
<div>
<button onClick={clickHandler}>Update myData and show in Console</button>
</div>
);
}

Resources