I have the following state:
users: {
'user-0': {
id: 'user-0',
title: 'Bob'
},
'user-1': {
id: 'user-1',
title: 'John'
},
...
I would like to change user-1's id by user-12 for example:
users: {
'user-0': {
id: 'user-0',
title: 'Bob'
},
'user-12': {
id: 'user-12',
title: 'John'
},
...
What is the easiest way to do that with the reducer ?
I was thinking about copying the user-1 data to a new entry by changing the ids, but is there a better way?
Without mutating data:
let data = {
users : {
'user-0': {
id: 'user-0',
title: 'Bob'
},
'user-1': {
id: 'user-1',
title: 'John'
},
'user-2': {
id: 'user-2',
title: 'Bohn'
}
}
}
let dataCopy = {
...data,
'users' :{
...data.users,
'user-12' : {
...data.users['user-1'],
id: 'user-12'
}
}
}
delete dataCopy.users['user-1'];
You need to make a deep copy of your object and only change that copy's properties. Do not mutate the original object. I am using spread operator and delete
Remember this is assuming your users follow the same structure.
First Copy user-1 data and add a new key user-12 and set its value as user-1. then update the id property of user-12 and remove user-1 key from the state.
users["user-12"] = {...users["user-1"], id:"user-12"};
// remove user-1 key from users state
delete users["user-1"]
Related
I'm writing a back code using NodeJs to fetch some data from backend, I want dataBase data to be like this
like this:
data = [{
name: "Admin",
id: '1',
children: [
{ name: "Admin", id: "1" },
{ name: "groupe1", id: "2" },
{
name: "groupe2", id: "1455", children: [
{ name: "groupe2", id: "1455" },
{ name: "gro", id: "5444" },
{ name: "hhrr", id: "45" }
]
}
]
}]
the idea is simple we have a list of group each group has a parent I want to display all the groups list in an hierarchical way the top one of the tree is done
Some groups are parents and groups in the same time and some others are only groups if the group is not parent we add an object with its name and ID in the array of children of his parent
if this groups is a parent that's mean it has children we add an object with its ID and name in the array of children of his parents, and we add property children for the object which is array named children with for the first time an object with the name and the id of the group etc...
i tryed to do this but it did not work
const getParentsByType = async ({ name, _id }) => {
let parentResult = [
{
id: _id,
name: name,
children: [
{
id: _id,
name: name,
},
],
},
];
parentResult= await findParent(_id, parentResult[0].children, 0);
return parentResult;
};
const findParent = async (parentId, parentResult, itemPos) => {
let children = await Models.GroupModel.find({ parent: parentId, status: true }).select('name _id');
for (let i = 0; i < children.length; i++) {
let childrenList = await Models.GroupModel.find({ parent: children[i]._id, status: true }).select('name _id');
if (childrenList.length != 0) {
parentResult.push(buildParentWithChild(children[i]._id, children[i].name));
findParent(children[i]._id,parentResult.children[i],itemPos++)
} else {
parentResult.push(buildParent(children[i]._id, children[i].name));
}
}
return parentResult
};
and this the model of the data base
const Group = mongoose.Schema({
name: {
type: String,
required: true,
},
status: {
type: Boolean,
required: true,
},
parent: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Group',
},
});
i had two days trying to resolve tis but with no result
i need some helps and Thank you
Try parsing your returned data. It validates your data as objects i dont see any problem with your function regardless i still have no idea what format your a trying to build.
let children = JSON.parse(JSON.stringify(await Models.GroupModel.find({ parent: parentId, status: true }).select('name _id')));
let childrenList = JSON.parse(JSON.stringify(await Models.GroupModel.find({ parent: children[i]._id, status: true }).select('name _id')));
If I understand you right, you want to convert the array returned by Models.GroupModel.find, and which looks like
var dbresult = [
{_id: "1", parent: null, name: "one"},
{_id: "2", parent: "1", name: "two"}
];
into a hierarchical structure. This can be done with a function that adds all children of a given parent p, including, recursively, their children. Like the following:
function children(p) {
var result = [];
for (r of dbresult) if (r.parent === p) {
var row = {_id: r._id, name: r.name};
var chld = children(r._id);
if (chld.length > 0) row.children = chld;
result.push(row);
}
return result;
}
console.log(JSON.stringify(children(null)));
Note that this approach requires only one database access (to fill the dbresult) and is therefore probably faster than your findParent function.
I try to add new arrays and values in a state.
I'm using react-beautiful-dnd to display this state datas.
my initial state :
const initialData = {
users: {
'user-1': { id: 'user-1', name: 'John'},
'user-2': { id: 'user-2', name: 'Patrick'},
'user-3': { id: 'user-3', name: 'Malorie'},
'user-4': { id: 'user-4', name: 'Eric'},
'user-5': { id: 'user-5', name: 'Bob'},
'user-6': { id: 'user-6', name: 'Blob'}
},
areas: {
'area-0': {
id: 'area-0',
title: 'Main Area',
userIds: ['user-1', 'user-2','user-3', 'user-4','user-5', 'user-6']
},
'area-1': {
id: 'area-1',
title: 'Area 1',
userIds: []
},
'area-2': {
id: 'area-2',
title: 'Area 2',
userIds: []
}
},
areaOrder: ['area-0','area-1', 'area-2'],
}
class MyClass {
constructor() {
super();
this.state = {
data: initialData,
}
}
...
}
I have a dropdown menu to choose the number of areas I want to display in total, when I trigger it, I try to add the new areas in the 'areas' array and in 'areOrder' array.
If I update the number of areas again, I need to reset the state to 'initialData'.
the code in MyClass:
// apply is triggered by the dropdown menu
apply = (numOfAreas) => {
// clear state to initial data
this.setState({
data: initialData
})
for (let i = 3; i <= numOfBOR; i++ ) {
this.addNewArea(i);
}
}
addNewArea = (newRoomId) => {
const areas = { ...this.state.data.areas };
let p = "area-";
let key = newAreaId;
const newAreaKey = p.concat(key);
const areaTitle = "Area ".concat(newAreaId);
let obj = [];
obj[newAreaKey] = { id: newAreaKey, title: areaTitle, userIds: [] };
const currentAreas = { ...areas };
const newAreaObj = Object.assign(currentAreas, obj);
const newState = {
...this.state.data,
areas: newAreaObj,
areaOrder: [...this.state.data.areaOrder, newAreaKey]
};
this.setState({data: newState});
};
When I use the code above, only the last area is displayed(i.e. when I chose 8 areas, the area 8 is display after area 2)
I'm aware that setState is asynch, so I'd like to know which method will allow me to do what I want.
In your case setState doesn't use previous state, so each setState change areas to its initial value plus one new element. You can use this.setState(prevState => newState) to get previous state.
I have this array:
const chats = [
{ id: "chat-1", msg: { text: "World", date: (a date) } },
{ id: "chat-2", msg: { text: "Hello", date: (a date) } },
];
After receiving updates from my database, I receive this object:
// The second chat with update data
{ id: "chat-2", msg: { text: "Bye", date: (a date) } },
How can I (using ES6) replace the chat object from the original chats array and move it to the first index?
For now, I am doing this, but I am looking for a fastest way (smaller O)
// Get the modified chat
const modifiedChat = response.data;
// Search the modified chat in the chats array by id
const chatIndex = chats.findIndex(
(chat) => chat.id === modifiedChat.id
);
// Finally, using spread syntax, add the updated chat to the head of our current chats array
chats = [
modifiedChat,
...chats.slice(0, chatIndex),
...chats.slice(chatIndex + 1),
];
You can do the following,
const chats = [
{ id: "chat-1", msg: { text: "World", date: '' } },
{ id: "chat-2", msg: { text: "Hello", date: '' } },
];
const modifiedChat = { id: "chat-2", msg: { text: "Bye", date: '' } };
const newChats = [modifiedChat, ...chats.filter(item => item.id !== modifiedChat.id)];
console.log(newChats);
You can do something similar to how LRU cache works. You can now access every chat in O(1)
I am trying to update a nested value of an object using the spread operator. This is my first time using this and I believe I am pretty close to achieving my end goal but I just can't seem to figure out what I actually need to do next.
I have an array which is structured like this:
[
{
name: "Category 1",
posts: [
{
id: 1,
published: false,
category: "Category 1"
},
{
id: 2,
published: true,
category: "Category 1"
}
]
},
{
name: "Category 2",
posts: [
{
id: 3,
published: true,
category: "Category 2"
},
{
id: 4,
published: true,
category: "Category 2"
}
]
}
]
On the click of a button I am trying to update the published value, and as I am using React I need to set the state. So it got recommended to me that I update using the spread operator.
onPostClick(post) {
post.pubished = !post.published;
this.setState({...this.state.posts[post.category], post})
}
If I log out the result of {...this.state.posts[post.category], post} I can see that the published is getting added to the parent which forms:
{
name: "Category 1",
published: false,
posts: [
...
]
}
Obviously this isn't the intended result, I want it to update the actual object within the posts object.
I have tried to do something like this.setState({...this.state.posts[post.category].posts, post}) but I get a message that it is undefined.
You can't access your data with this.state.posts[post.category]. posts data in the objects of the array.
You can make a filter to find your category object in array and change its posts value.
onPostClick(post) {
//CLONE YOUR DATA
var postArray = this.state.posts;
//FIND YOUR CATEGORY OBJECT IN ARRAY
var categoryIndex = postArray.findIndex(function(obj){
return obj.name === post.category;
});
//FIND YOUR POST AND CHANGE PUBLISHED VALUE
postArray[categoryIndex].posts.forEach(function(item){
if (item.id === post.id) {
item.published = !item.published;
}
});
//SET TO STATE TO RERENDER
this.setState({ posts: postArray});
}
This should work if your name of the state is true.
just adding, we know there are many ways to succeed, maybe you also want to try this way too..
onPostClick = post => {
let published = this.state.data.map((item, i) => {
item.posts.map((item_post, i) => {
if (item_post.category === post.category) {
item_post.published = !post.published;
}
});
});
this.setState({ ...this.state.data, published });
};
I have an issue with updating the immutable redux and quite nested data. Here's an example of my data structure and what I want to change. If anyone could show me the pattern of accessing this update using ES6 and spread operator I would be thankful. 😀
const formCanvasInit = {
id: guid(),
fieldRow: [{
id: guid(),
fieldGroup: [
{ type: 'text', inputFocused: true }, // I want to change inputFocused value
{ type: 'text', inputFocused: false },
],
}],
// ...
};
This should do the trick, assuming the data is set up exactly as shown, with the given array indices:
const newData = {
...formCanvasInit,
fieldRow: [{
...formCanvasInit.fieldRow[0],
fieldGroup: [
{ ...formCanvasInit.fieldRow[0].fieldGroup[0], inputFocused: newValue },
...formCanvasInit.fieldRow[0].fieldGroup.slice(1, formCanvasInit.fieldRow[0].fieldGroup.length)
]
}]
};
If index of the element to be changed is to be determined dynamically, you'll need to use functionality such as filter to find and remove the array element you're updating, and then spread the corresponding subarrays by editing the structure of the call to slice.
Try using Immutability Helper
I think in your structure, like this
let news = update(formCanvasInit, {
fieldRow: [{
fieldGroup: [
{ $set: {type: "number", inputFocused: false}}
]
}]
})
I've tried it
Click Me
This is a longer solution but might help you as your redux state grows. I've also changed some of the values in the original state to make a clearer explanation.
const formCanvasInit = {
id: 'AAAAXXXX',
fieldRow: [
{
id: 1001,
fieldGroup: [
{type: 'text1', inputFocused: true}, // I want to change inputFocused value
{type: 'text2', inputFocused: false},
]
},
{
id: 1002,
fieldGroup: [
{type: 'text3', inputFocused: true},
{type: 'text4', inputFocused: true},
]
}
]
};
// the id of the field row to update
const fieldRowID = 1001;
// the value of the field type to update
const fieldTypeValue = 'text1';
const fieldRow = [...formCanvasInit.fieldRow];
// obtain the correct fieldRow object
const targetFieldRowIndex = formCanvasInit.fieldRow.findIndex(fR => fR.id === fieldRowID);
let fieldRowObj = targetFieldRowIndex && formCanvasInit.fieldRow[targetFieldRowIndex];
// obtain that fieldRow object's fieldGroup
const fieldGroup = [...fieldRowObj.fieldGroup];
// obtain the correct object in fieldGroup
const fieldIndex = fieldGroup.findIndex(fG => fG.type === fieldTypeValue);
const fieldToChange = fieldIndex && fieldGroup[fieldIndex];
// replace the old object in selected fieldGroup with the updated one
fieldGroup.splice(fieldIndex, 1, {...fieldToChange, inputFocused: false});
// update the target fieldRow object
fieldRowObj = {...fieldRowObj, fieldGroup};
// replace the old fieldGroup in selected fieldRow with the updated one
fieldRow.splice(targetFieldRowIndex, 1, fieldRowObj);
// create the new formCanvasInit state
const newFormCanvasInit = {...formCanvasInit, fieldRow};