Redux store immutable pattern for nested data in array? - javascript

I've got a simple JSON data array that looks like this (it's the same in my Redux store and I store it under properties):
[
{
"id": "room",
"name": "Room",
"description": "Just a room",
"foo": "bar",
},
{
"id": "apartment",
"name": "Apartment",
"description": "just an apartment",
"foo": "bar",
}
]
It has to be an array because I'm mapping over it:
{properties.map(property =>
<Property
id={property.id}
name={property.name}
description={property.description}
foo={property.foo}
/>)}
This way I have two properties rendered in my app.
The question is - how do I update "foo"in Redux?
This my reducer currently written according to the docs:
case 'UPDATE_FOO':
return {
...state,
properties: {
...state.properties,
[action.id]: {
...state.properties[action.id],
foo: action.fooData,
}
}
}
Of course it throws TypeError: Cannot read property 'room' of undefined because I'm trying to access state.properties["room"] and this does not exist.
I've been thinking about reshaping my JSON and Redux store, but once I change it to named objects I can't map over it...
Thank you!

Change your store to be an object, and generate the array, when you need to render it, by converting it to an array, using Object.values():
{Object.values(properties).map(property => (
<Property key={property.id} {...property} />
)}
If the order might change (sorting for example), you need to have another array with the ids to hold the order (see redux normalized state):
{
properties: {
room: {
"id": "room",
"name": "Room",
"description": "Just a room",
"foo": "bar",
},
apartment: {
"id": "apartment",
"name": "Apartment",
"description": "just an apartment",
"foo": "bar",
}
}
}
{
properties: {
room: {
"id": "room",
"name": "Room",
"description": "Just a room",
"foo": "bar",
},
apartment: {
"id": "apartment",
"name": "Apartment",
"description": "just an apartment",
"foo": "bar",
}
},
order: ['apartment', 'room']
}
{order.map(id => (
<Property key={id} {...properties[id]} />
)}

If you want to update the store using but the Id. You can look up for the one element (you're trying to edit) in array of properties using the id, then to update it:
case 'UPDATE_FOO':
const newProperties = state.properties.map(property => {
if(property.id === action.id) {
return { ...property, foo: action.fooData}
}
return property;
})
return {
...state,
properties: newProperties
}
}

Related

How to map through nested objects of Laravel collection in React JS

In my front-end I am trying to map through nested objects which is coming from back-end Laravel collection:
[
{
"id": 1,
"name": "Chips",
"product_categories_id": 1,
"category": {
"id": 1,
"category": "Chips",
"brand": "Bombay Sweets"
}
},
{
"id": 2,
"name": "Book",
"product_categories_id": 2,
"category": {
"id": 2,
"category": "Shoe",
"brand": "Nike",
}
}]
I want to display the product name and related category name from nested object. My approach is:
products.map((product)=>{
console.log(product.name)
product.category.map((category)=>(
console.log(category.category)
))
})
which is not working at all. I spent huge amount of time to solve yet no luck.
the error it shows:
ProductListContainer.js:58 Uncaught TypeError: item.category.map is not a function
map method works only with Array. You can use product.category.category to access the value.
Finally solved by this:
products.map((product) => {
console.log(product.name)
Object.entries(product.category).map(() => (
console.log(product.category.category, product.category.brand)
))
})

Creating an new object from an existing object in javascript

I am going through a challenge from devchallenges.io, Shoppingify challenge. Having read the prompt, I proceeded to create a model which has the following format when a request is made.
{
"user": 1,
"_id": 3393220221,
"name": Chicken,
"category": "Meat",
"note": "This is an example note",
"image_url": "www.exampleurl.com"
}
The issue I'm having is that the component expects the object in the following format.
{
"category": "Meat",
"items": [
{
"user": 1,
"_id": "3393220221",
"name": "Chicken",
"note": "This is an example note",
"image_url": "www.exampleurl.com"
}
]
}
The link to the challenge is https://devchallenges.io/challenges/mGd5VpbO4JnzU6I9l96x for visual reference.
I'm struggling with how to modify the object response from the request. I want to be able to find occurances of the same category name and push the items onto a new object as shown.
const users = [
{
"user": 1,
"_id": 3393220221,
"name": "Chicken",
"category": "Meat",
"note": "This is an example note",
"image_url": "www.exampleurl.com"
}
];
function modifyUserObject(users) {
const result = {};
users.forEach(user => {
if (!result[user]) {
result[user] = {
category: user.category,
items: []
}
}
//code here..if want to remove user properties like user
result[user].items.push(user);
});
return Object.values(result);
}
modifyUserObject(users);
Hope this will be helpful! Happy coding...
The value Chicken is not defined. Is this a typing error by you? Anyway this should do the trick:
const obj = {
user: 1,
_id: 3393220221,
name: "Chicken",
category: "Meat",
note: "This is an example note",
image_url: "www.exampleurl.com",
};
function createObj(arg) {
let result = {
category: arg.category,
items: [
{
user: arg.user,
_id: arg._id,
name: arg.name,
note: arg.note,
image_url: arg.image_url,
},
],
};
return result;
}
console.log(createObj(obj));
Edit:
If you want to create a new object that is not related to the old one (deep copy) you need to do JSON.parse(JSON.stringify(obj)) to not change the values of the original object.

Losing values from redux object when spreading into new object

I'm fetching data from redux store with useSelector.
const customerProduct = useSelector((state) => state.objects.customersProducts[match.params.customerProductId]);
If I log the data it is displayed like this in the console:
Once I try to use spread operator to create a new object, it would lose all the values with (...).
Like this:
const updatedCustomerProduct = { ...customerProduct, newValue: "abc" };
I would get an output like this:
const uptdatedCustomerProduct =
{
"id": "AALzgGxtlg",
"_objCount": 6360,
"newValue": "abc",
"className": "customerOfferMetadata"
}
What's going on here? How could I handle these values? If I copy the object from the console the object is perfectly visible.
Even in redux dev tools the data is displayed like this:
{
"entityInfo": {
"productId": 441,
"bundleOfferId": 22
},
"title": {
"us": "Special Offer"
},
"desc": {
"us": "6 months"
},
"order": 0,
"enabled": true,
"entityType": "product",
"detailsUrl": "www.google.com",
"thumb": {
"__type": "Pointer",
"className": "Resource",
"objectId": "12345"
},
"createdAt": "2021-02-26T18:48:25.358Z",
"updatedAt": "2021-09-21T21:41:49.384Z",
"clientId": 1,
"objectId": "AALzgGxtlg"
}
I'm not sure what code is generating those objects for you, but when you see properties in the console that are semitransparent, they are non-enumerable. This means that when applying the spread operator, they are not iterated over, and hence they do not make it into the new object.
To make all properties enumerable, check out the question Make all properties enumerable.

Nested forEach issue

I have two arrays of object, the first array (printers, around 80 elements) is made of the following type of objects:
[{
printerBrand: 'Mutoh',
printerModel: 'VJ 1204G',
headsBrand: 'Epson',
headType: '',
compatibilty: [
'EDX',
'DT8',
'DT8-Pro',
'ECH',
],
cartridges: [],
},
....
]
The second array (cardridges, around 500 elements) is made of the following type of objects:
[
{
"customData": {
"brand": {
"value": {
"type": "string",
"content": "ECH"
},
"key": "brand"
},
"printer": {
"value": {
"type": "string",
"content": "c4280"
},
"key": "printer"
}
},
"name": "DT8 XLXL",
"image": {
"id": "zLaDHrgbarhFSnXAK",
"url": "https://xxxxxxx.net/images/xxxxxx.jpg"
},
"brandId": "xxxxx",
"companyId": "xxxx",
"createdAt": "2018-03-26T14:39:47.326Z",
"updatedAt": "2018-04-09T14:31:38.169Z",
"points": 60,
"id": "dq2Zezwm4nHr8FhEN"
},
...
]
What I want to do first is to is to iterate through the first array and and then iterate for all the cardridge available: if a the value customData.brand.value of a cardridge is included inside the array 'compatibility' of a printer, then I have to add this cardridge object inside the cardridges array of this printer. I have tried but somehow the iteration doesn't take place correctly. This is what I tried:
printers.forEach((printerItem) => {
const printer = printerItem;
printer.compatibilty.forEach((compatibilityItem) => {
const compatibility = compatibilityItem;
cardridges.forEach((cartridge) => {
if (compatibility === cartridge.customData.brand.value.content) {
printer.cartridges.push(cartridge);
}
});
});
});
What am I doing wrong?
You're accessing the wrong property. It should be cartridge.customData.brandName.value.content, carefully note brandName.value rather than brand.value
Your issue is that you're accessing it by the wrong property - brand and not brandName.
Furthermore, if you're targeting everything but IE, you could simplify your nested for loops to utilize some fancy ES6 array methods.
printers.forEach((p) => {
p.cartridges.push(cartridges.filter((c) => {
const brandName = c.customData.brandName.value.content;
return p.compatibilty.includes(brandName);
}));
});

How to delete a paticular Object in an array inRethinkDB

I am Just trying to learn RethinkDB.I am little Bit Confused That how to delete an single Object in an array,What is the Exact query I have to use if i have to delete this Object
{
"name": "Ram" ,
"username": "B97bf210-c4d2d-11e6-b783-07b5fev048705"
}
from whoLikedIt Array
My data
{
"comments": [ ],
"id": "c242c74d-03d9-4963-9a22-4779facb8192" ,
.....
"views": 0 ,
"whoLikedIt": [
{
"name": "Vignesh Warar" ,
"username": "d97bf210-c42d-11e6-b783-07b5fe048705"
},
{
"name": "Ram" ,
"username": "B97bf210-c4d2d-11e6-b783-07b5fev048705"
},
]
.....
}
My Try
r.db('image').table('posts').get('c242c74d-03d9-4963-9a22-4779facb8192').update(
{whoLikedIt:r.row('whoLikedIt').filter({username:"B97bf210-c4d2d-11e6-b783-07b5fev048705"}).delete()}
)
Throws Me a error
e: Cannot nest writes or meta ops in stream operations. Use FOR_EACH instead in:
You want:
r.db('image').table('posts').get('c242c74d-03d9-4963-9a22-4779facb8192').update(function(row) {
return {whoLikedIt: row('whoLikedIt').filter(function(obj) {
return obj('username').ne("B97bf210-c4d2d-11e6-b783-07b5fev048705");
})};
})

Categories