How to solve Error Use object destructuring prefer-destructuring - React - reactjs

I am stuck with an ugly issue which I am unable to resolve. I am beginner in React.
This is my Code
handleCheckChildElement(event) {
let items = this.state.items;
items.forEach(items = () => {
if(items.value === event.target.value) {
items.isChecked = event.target.checked;
}
});
this.setState({ items });
}
This is the image of the error -

Use below code for line #55 :
let {items}= {...this.state};
Read more here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring

Your code can be improved to something like below. Please find relevant comments in the code below for your better understanding
handleCheckChildElement(event) {
const { items } = this.state; //extract state values like this to a const variable
const newItems = items.map(item => { //do map on items because map returns a new array. It’s good practice to use .map than forEach in your case
if(item.value === event.target.value) {
item.isChecked = event.target.checked;
return item; //return updated item object so that it will be pushed to the newItems array
}
return item; // return item because you need this item object as well
});
this.setState({ items: newItems}); //finally set newItems array into items
}

handleCheckChildElement(event) {
const items = this.state.items;
const filtered = items.filter(item => item.value === event.target.value)
.map(item => item.isChecked = event.target.checked) ;
this.setState({items : [...filtered] );
}

Related

React SetState Array with function

I have an array I wish to keep track of,
const [myArray, setMyArray] = useState([]);
I want this to be an array of MyCustomObject
I am then creating the array in my useEffect():
const newObject = new MyCustomObject(); //initiate object and set values (removed to simplify)
setMyArray(newObject);
I want to override myArray rather than push onto the list. How do I do this?
EDIT:
I think my initial code example was misleading. I've now copy/pasted my actual code for full transparency of the problem..
//this is imported further above
// import CustomerTradeDto from "Models/Customer/CustomerTradeDto";
const [arrayOfCustomerProviderRefTrades, setArrayOfCustomerProviderRefTrades] = useState([]);
useEffect(() => {
const newArray = customer.customerProviderRefList.map((providerRef) => {
return {
customersWithTrade: customerTradeList.customerTradeList.find(trade => trade.customerProviderRef == providerRef.externalRefId)
}
})
setArrayOfCustomerProviderRefTrades([...arrayOfCustomerProviderRefTrades, newArray]);
});
Error I am receiving: Type '{ customersWithTrade: CustomerTradeDto | undefined; }[]' is not assignable to type 'never'
You should use the spread operator.
Try this
setMyArray([...newObject]);
Hope this helps
You want the state to be an array of an object, so set the state likewise.
Solution
setMyArray([...myArray, newObject])
This should work smoothly.
I assume that you have array of object and want to override one object of it with new one
you can do it by using prevState and findIndex
like this:
const [myArray, setMyArray] = useState([]);
const newObject = new MyCustomObject();
setMyArray((prevState)=>{
let newArr = prevState;
if(newArr.length === 0 ){
return [newObject]
}
let arrIndex = newArr.findIndex(item => item.id === newObject.id)
if(arrIndex !== -1){
newArr[arrIndex] = newObject
}
return newArr
});
and if newObject is array of new objects you can have a loop for it
like this:
setMyArray((prevState)=>{
let newArr = prevState;
if(newArr.length === 0 ){
return [newObject]
}
newObject.forEach(obj=>{
let arrIndex = newArr.findIndex(item => item.id === obj.id)
if(arrIndex !== -1){
newArr[arrIndex] = obj
}
})
return newArr
});
and for typescript error you can set typeof arrayOfCustomerProviderRefTrades state in this way :
const [arrayOfCustomerProviderRefTrades, setArrayOfCustomerProviderRefTrades] = useState<Array<{ customersWithTrade: CustomerTradeDto | undefined }[]>>([]);

Delete an array item from an array in reactjs [duplicate]

I am trying to remove a (semi) deeply nested item from an array using setState but it doesn't seem to be working. My state is structured as follows:
state = {
currentSeries: null,
currentRowIndex: null,
rows: [
{
id: shortid.generate(),
nodes: [],
series: [], // array with item I want to remove
},
],
};
and my remove item call:
onRemoveModelElementClick = (rowId, modelElementId) => {
this.setState((prevState) => {
const index = prevState.rows.findIndex(x => x.id === rowId);
const series = prevState.rows[index].series.filter(s => s.id !== modelElementId);
return series;
});
};
I tried spreading the remaining state is several ways but it does not seem to update properly. I the rowId and modelElementId are correct and I can verify they do filter the correct item out. I am just having trouble on what to return. I know it is something simple but for the life of me I can't see it.
My recommendation would be to use .map to make things are bit easier to digest. You can then write it like so:
onRemoveModelElementClick = (rowId, modelElementId) => {
const updatedRowsState = this.state.rows.map(row => {
// this is not the row you're looking for so return the original row
if (row.id !== rowId) {
return row;
}
const filteredSeries = row.series.filter(s => s.id !== modelElementId);
return {
// spread properties (id, node, series)
...row,
// overwrite series with item filtered out
series: filteredSeries,
};
});
// since rest of the state doesn't change, we only need to update rows property
this.setState('rows', updatedRowsState);
}
Hope this helps and let me know if you have any questions.
I think the issue here is how your code uses setState. The setState function must return an object. Assuming your filtering functions are correct as you describe, return an object to update the state:
return { series };
setState documentation
Here is what I did to get it working in case it can help someone else:
onRemoveModelElementClick = (rowId, modelElementId) => {
this.setState((prevState) => {
const updatedRowState = prevState.rows.map((row) => {
if (row.id !== rowId) {
return row;
}
const filteredSeries = row.series.filter(s => s.id !== modelElementId);
return {
...row,
series: filteredSeries,
};
});
return {
rows: updatedRowState,
};
});
};
All credit to Dom for the great idea and logic!

update react state using previous data

This is a follow up question to this question:
Why calling react setState method doesn't mutate the state immediately?
I got a React component with a form which can be used to add items or edit a current item. The form is being saved as a state of the component along with all its values.
When submitting the form I'm doing this:
const onSubmitForm = () =>
{
if(editedItem) //the item to edit
{
EditSelectedItem();
setEditedItem(undefined);
}
else
{
//handle new item addition
}
clearFormValues();
setEditedItem(undefined);
}
And the edit method:
const EditSelectedItem = () =>
{
setItemsList(prevItemsList =>
{
return prevItemsList.map(item=>
{
if(item.id !== editedItem.id)
{
return item;
}
item.name = formSettings["name"].value ?? "";
item.description = formSettings["description"].value ?? "";
item.modified = getNowDate();
return item;
});
})
}
The problem is that because the setItemsList is not being called synchronously, the clearFormValues(); in the submit form method is being called before, and I lose the form's old values (in formSettings)..
How can I keep the old values of formSettings when the setItemsList is called?
The solution is easy here, you can store the formValues in an object before using it an setItemsList
const EditSelectedItem = () =>
{
const values = {
name: formSettings["name"].value ?? "";
description: formSettings["description"].value ?? "";
modified: getNowDate();
}
setItemsList(prevItemsList =>
{
return prevItemsList.map(item=>
{
if(item.id !== editedItem.id)
{
return item;
}
return {...item, ...values};
});
})
}

React native push with multiple key and value

I have a group of checkboxes, whenever I select a checkbox I need to push an array of data, like { 'index':1, 'photo':'sample.png' } to state, and whenever I unselecting the checkbox, I need to remove it from the state. after I need to loop through the state to get index and photo to be used
handleSelection = async (media, index, isSelected) => {
alert(index);
if (isSelected == true) {
this.state.mediaSelected.push(media.photo);
} else {
this.state.mediaSelected.splice(this.state.mediaSelected.indexOf(media.photo), 1);
}
console.warn(this.state.mediaSelected);
}
this is working for single value without the key, is there any way to push it with key and value?
You should always update state with this.setState in your case would be something like this:
handleSelection = async (media, index, isSelected) => {
alert(index);
if (isSelected == true) {
this.setState({
mediaSelected: this.state.mediaSelected.push({
index,
photo: media.photo
})
});
} else {
this.setState({
mediaSelected: this.state.mediaSelected.splice(this.state.mediaSelected.indexOf(media.photo), 1)
});
}
console.warn(this.state.mediaSelected);
}
Try this:
Sorry I am working as well as answering your question so it is taking time.
handleSelection = async (media, index, isSelected) => {
let selectPhotosObj = this.state.selectPhotosObj || [];
if (isSelected == true) {
const data = { index, photo: media.photo };
//this.state.selectedPhotoObj will be the container for your object.
selectPhotosObj.push(data)
//need to set the new Array of Object to the state.
this.setState({ mediaSelected: media.photo, selectPhotosObj });
} else {
const removedPhoto = this.state.mediaSelected.filter(value => value !== media.photo);
selectPhotosObj = this.state.selectedPhotosObj.filter(value => value.index !== index);
this.setState({
mediaSelected: removedPhoto,
selectPhotosObj
})
}
console.warn(selectPhotosObj);
}

component is getting loaded on 2nd iteration in react

I am using react plus d3 for my graph. now I am merging two different arrays to populate y graph. but one of the array is showing undefined to me, I checked in reducer both array gets the data properly. but if I go and come back again to the page it is working fine. so means only whenever my DOM is clear it is giving me problem. below is my reducer
const VolumeQuantity = MixMergeGroup.map(data => {
return data.map
.map(mixdata => mixdata.world_volume * sum)
.reduce((prev, curr) => prev + curr);
});
var VolumeQuantityGraph = [];
var tempObj_world = null;
MixMergeGroup.map((data, index) => {
tempObj_world = {};
tempObj_world['world_name'] = data.key;
tempObj_world['world_volume'] = VolumeQuantity[index];
VolumeQuantityGraph[index] = tempObj_world;
});
var overGraph = [];
currentYearData.map((data, index) => {
let temp = {};
temp.key = data.name;
let values = {};
values.value = data.forcasted_volume;
values.label = data.year + ' Volume';
temp.values = [values];
overGraph[index] = temp;
});
return {...state,overallGraph: overGraph,MixVolumeGraph:VolumeQuantityGraph}
here is my component where I use this value
componentWillReceiveProps(nextProps) {
if (
this.state.graphData.length == 0 &&
nextProps.MixVolumeGraph !== undefined
) {
nextProps.overallMixData.forEach(function(element) {
let filtereddata = nextProps.MixVolumeGraph.filter(
data => data.name === element.name
);
element.world_volume = filtereddata[0].volume;
});
console.log('nextprops', nextProps);
this.setState({ graphData: nextProps.overallMixData });
}
}
can please anyone let me know why on first instance its not giving me any value?
from docs React doesn't call componentWillReceiveProps with initial props during mounting. It only calls this method if some of component's props may update. Calling this.setState generally doesn't trigger componentWillReceiveProps.
so you need to call this method in componentdidmount to start it on first mount
edit: sample:
processData(nextProps) {
if (
this.state.graphData.length == 0 &&
nextProps.MixVolumeGraph !== undefined
) {
nextProps.overallMixData.forEach(function(element) {
let filtereddata = nextProps.MixVolumeGraph.filter(
data => data.name === element.name
);
element.world_volume = filtereddata[0].volume;
});
console.log('nextprops', nextProps);
this.setState({ graphData: nextProps.overallMixData });
}
}
componentWillReceiveProps(nextProps) {
processData(nextProps);
}
componentDidMount() {
processData(this.props);
}
I had used componentDidMount but it was giving me error Cannot read property 'props' of undefined this is because I was using foreach loop. I changed into map it is working now below is my update loop
this.props.overallWorldMixData.map(data => {
let filtereddata = this.props.MixVolumeGraph.filter(
dataName=> dataName.name === data.name
);
data.volume = filtereddata[0].volume;
});
I don't know the reason and I know it is not immutable solution, if anyone can clarify this I would be glad

Resources