I have come around this topic today.
I am trying to map an array and update it like this.
const editTask = (id, newTitle) => {
const updatedTodo = [...tasks].map(task => {
task.id === id ? {...task, title: newTitle} : task
});
setTasks(updatedTodo);
};
tasks is array of objects
One of my friends have told me that there is no need to copy the original array during map. because map itself returns the new array.
But as far as I know this array is considered as 2 level deep array and it needs to copy the original array too for the update of the object.
Can someone explain to me which way is correct and which is not? I am lost.
Thanks in advance
Your friend is right: map DOES return a new array (unlike forEach)
Since you're using react-hooks, creating a new array for the updated tasks is considered redundant and the best way to achieve the same result is to do something like this:
const editTask = (id, newTitle) => {
setTasks((tasks) =>
tasks.map((task) => (task.id === id ? { ...task, title: newTitle } : task))
);
};
Related
I'm in the midst of cleaning up errors for a repo and I've come across this error where someone's trying to to assign a tag value object to a const variable inside of a map function. Here's its current form:
const BatchEditState = {
CURRENT: 'CURRENT',
DELETE: 'DELETE',
PUT: 'PUT',
}
handleShow = () => {
this.batchEditSet = {};
this.state.currentTags.map((tag) => {
this.batchEditSet[tag.tag_name] = BatchEditState.CURRENT;
});
};
As far as I've researched, one is definitely not supposed to go about it this way even if it does still function. I've seen plenty examples returning a jsx element, but I'm pretty sure that's not the point for this. I do know a map function is supposed to at least return a value however.
I attempted to use a spread operator and an implicit return, but that didn't work out. I also tried making a basic return & even though I'm not encountering any immediate errors in our application, I'm still not sure if this is the right way to go. Still fairly new at this, but appreciate any info, help, and education I can get
handleShow = () => {
this.batchEditSet = {};
this.state.currentTags.map((tag) => {
this.batchEditSet[tag.tag_name] = BatchEditState.CURRENT;
return(
BatchEditState.CURRENT
)
});
};
.map is only for creating new arrays by iterating over an existing array. While you want to iterate over an existing array, you don't want to create a new array - rather, you want to construct a plain object - so .map should not be used here. (The array you're constructing in your current code is going unused.)
To procedurally assign to properties of the object, do:
handleShow = () => {
this.batchEditSet = {};
this.state.currentTags.forEach((tag) => {
this.batchEditSet[tag.tag_name] = BatchEditState.CURRENT;
});
};
Or create an array of entries, then turn that array into an object.
handleShow = () => {
this.batchEditSet = Object.fromEntries(
this.state.currentTags.map(tag => [tag.tag_name, BatchEditState.CURRENT])
);
};
But also, doing this.batchEditSet = in the first place looks like a mistake in React. If this is a component, you should almost certainly be calling this.setState instead of mutating the instance.
I'm making a React-Native application. Thanks to everyone's help I could somehow make that work except for toggling YES and NO. Once the user clicks on a button I just want to check if that clicked item data already exists in the state, if so I want to update it. If it does not exist then it should be added to the state as a new Item.
I already coded the above logic, my code is working, but not returning correct output, elements are not adding or updating to the state array properly. How do I fix this code?
I want to generate output like this
[{
chelistid:231,
validiary : "YES",
remark : "Hello"
},{
chelistid:232,
validiary : "NO",
remark : "asddddd"
}]
My code
const [reqData, setReqData] = useState([]);
//Modify yes clicked
const yesClicked = (element) => {
let req = {
"chelistid": element.chelistid,
"validiary": "Yes",
"remark": element.remark
}
createCheckList(req);
}
//Modify no clicked
const noClicked = (element) => {
let req = {
"chelistid": element.chelistid,
"validiary": "No",
"remark": element.remark
}
createCheckList(req);
}
const createCheckList = (data) => {
const index = reqData.findIndex(x => x.chelistid === data.chelistid)
var modifiedArray = reqData
if (index !== -1) {
//Remove the element from the array
modifiedArray.splice(index, 1);
}
setReqData([modifiedArray, data]);
}
The problem is it seems like you are not spreading the array to append the data element. What you are doing by [modifiedArray, data] you are creating an array that contains an array and data something like [[modified array content here], data]. But actually, you want to append to modified array instead. For that, you need to expand the modified array by using ... which is called spread syntax. (Learn here) So, your code would look like:
setReqData([...modifiedArray, data]);
i currently have an object and inside this object i have multiple objects and Arrays. I want replace an Array inside this object with a new Array, so i thought of making a copy of the entire object and simple replace the Array i wan to change with the updated Array. My problem is i couldnt complete my code, i have the idea of how to do it but cant execute it.
setListings(listings=>
listings.map(item =>{
if(item.id === msg.id){
//console.log(item)
//console.log(item.Message)
const newMessages = [msg,...item.Messages]
//console.log(newMessages)
return console.log([msg,...item.Messages],{...item}) // just for testing purpose i
am returning a console log
to see what it will get me. Not correct.
}
return item;
})
);
So basically listings is my state variable, here console.log(item) prints out the entire object, console.log(item.Messages) prints out the current Messages Array which i want to replace, console.log(newMessages) prints out the new Messages Array which i want to replace the current Messages array with.
cartItem.map((food,index)=> {
if(food.food_id == newFoodItem.food_id && food.id == newFoodItem.id){
const AllFoodData = cartItem
AllFoodData[index] = newFoodItem
AsyncStorage.setItem('#Add_cart_Item', JSON.stringify(AllFoodData))
.then(() => {})
.catch(err => console.log(err))
ToastAndroid.showWithGravityAndOffset('Cart Replace Successfully',ToastAndroid.LONG,ToastAndroid.BOTTOM,25,50 )
}
})
So basically what i want to achieve here is to add the msg object to the existing Messages Array.
Since lsitings is an Array of objects using the .map i can spread through each object and check if the id of that object is each to my msg.id. if that is true then i want to return a copy the that specific listing and edit the Messages Array within [msg, ...item.Messages] otherwise return the existing item.
setListings(listings=> listings.map(item => {
if(item.id === msg.id) {
return {
...item,
Messages: [msg, ...item.Messages]
}
}
return item;
}));
});
createNewList = (id, input) => {
const foundCard = {...this.state.cards.find(card => id === card.id)};
this.setState(foundCard.list = [...foundCard.list, input]);
};
Hello everyone
There is an array of data (list), which is stored in the state for each object (card).
Problem: I can’t seem to add a new element to this array.
The way it is set up creates only one element and change it every time. But I need to create a new one every time. I tried to create a separate array, add to it using newArray.push (input) and then do this.setState (foundCard.list = [... foundCard.list, ... newArray])`, but have the same result.
I don’t use Redux, because I just started to learn React and I store everything in state yet.
Thanks in advance for your reply.
createNewList = (id, input) => {
const newCards = this.state.cards.map(card => {
if (card.id === id) card.list = [...card.list, input];
return card;
});
this.setState({
cards: newCards
});
};
I'm pretty new to vue/vuex/vuetify but starting to get the hang of it.
I have a problem though I haven't been able to solve properly.
I have an array of "projects" in my store. When deleting and adding items to the store via mutations the changes reflect properly in subcomponents referencing the array as a property.
However, changes to items in the array does not reflect even though I can see that the array in the store is updated.
The only way I got it to "work" with an update action was to either :
remove the project from the array in the store and then add it
use code that sort of does exactly the same as described above but like so:
state.categories = [
...state.categories.filter(element => element.id !== id),
category
]
But the problem with the above two methods is that the order of the array gets changed and I would really like to avoid that..
So basically, how would I rewrite my mutation method below to make the state reflect to subcomponents and keep the order of the array?
updateProject(state, project) {
var index = state.projects.findIndex(function (item, i) {
return item.id === project.id;
});
state.projects[index] = project;
}
You can use slice to inject edited project in correct position:
updateProject(state, project) {
var index = state.projects.findIndex(function(item, i) {
return item.id === project.id;
});
state.projects = [
...state.projects.slice(0, index),
project,
...state.projects.slice(index + 1)
]
}
or you can use JSON.parse(JSON.stringify()) to make a deep copy of object
updateProject(state, project) {
var index = state.projects.findIndex(function(item, i) {
return item.id === project.id;
});
state.projects[index] = project;
state.projects = JSON.parse(JSON.stringify(state.projects))
}