Using spread syntax in Reducer - javascript

I am trying to use the spread syntax to update the state inside the reducer
The state consists of an object, and the object has an array,
I would like to update all properties in the object, except for the array, which I would like to add the next state elements at the end. For example,
For example, if the state is
{
id: 4,
amount: 10,
arr: [
name: "peter",
name: "john"
]
}
and the action
{
id: 7,
amount: 7,
arr: [
name: "sally",
name: "maria"
]
}
I would like to get as a result of using the spread syntax
{
id: 7,
amount: 7,
arr: [
name: "peter",
name: "john",
name: "sally",
name: "maria"
]
}
taking the id and amount of the action, and concatenating the array
Thank you

Simply keep spreading props.
spread your current state
spread action's payload
change properties as needed
const INITIAL_STATE = {
id: 4,
amount: 10,
arr: [
{ name: "peter" },
{ name: "john" },
],
}
function reducer(state = INITIAL_STATE, action) {
switch (action.type) {
default: return state
case 'ANY_ACTION':
return {
...state,
...action.payload,
arr: [
...(state.arr || []),
...action.payload.arr,
]
}
}
}
const action = {
type: 'ANY_ACTION',
payload: {
id: 7,
amount: 7,
arr: [
{ name: "sally" },
{ name: "maria" },
]
}
}
const state = reducer(undefined, action)
console.log(state)

First of all your structure is invalid, the correct structure would look like
{
id: 4,
amount: 10
data: [
{name: "peter"},
{name: "john"}
]
}
and then you could use spread operator to update state assuming action.payload to be
{
id: 7,
amount: 7
data: [
{name: "sally"},
{name: "maria"}
]
}
like
case 'WHATEVER_ACTION':
return {
...state,
id: action.payload.id,
amount: action.payload.amount,
data: [...state.data, ...action.payload.data]
}
Check the documentation of Spread syntax to understand its usage more

Related

How do I check that the correct objects are being returned via a function (expect function returns [Function Anonymous])?

I have a function:
const sort =
(pets,attribute) =>
_(pets)
.filter(pets=> _.get(pets, attribute) !== null)
.groupBy(attribute)
.value()
Some data:
const pets= [{
id: 1,
name: 'snowy',
},
{
id: 2,
name: 'quacky',
},
{
id: 3,
name: 'snowy',
age: 5,
},
{
id: null,
name: null,
age: null
}
]
const attribute = 'name'
I am currently trying to write some Jest unit tests for this, that tests if the function returns the correct resultant object after being sorted based off an attribute.
The result of:
sort(pets,attribute) is something like this:
{
snowy: [ { id: 1, name: 'snowy' }, { id: 3, name: 'snowy', age: 5} ],
quacky: [ { id: 2, name: 'quacky' } ]
}
Is there a way I can do a expect to match the two objects snowy and quacky here?
The thing I want to test for is that the objects are being correctly grouped by the key.
I've tried using something like
const res = sort(users,key)
expect(res).toEqual(
expect.arrayContaining([
expect.objectContaining({'snowy' : [ { id: 1, name: 'snowy' }, { id: 3, name: 'snowy', age: 5 } ]},
expect.objectContaining({'quacky' : [ { id: 2, name: 'quacky' } ]}))
])
)
which doesn't seem to work, the received output seems to output:
Expected: ArrayContaining [ObjectContaining {"snowy": [{"id": 1, "name": "snowy"}, {"age": 5, "id": 3, "name": "snowy"}]}]
Received: [Function anonymous]
I am unsure what the best method to test this kind of function is either so advice on that would be appreciated.
If this is what your arrangeBy() returns:
{
snowy: [ { id: 1, name: 'snowy' }, { id: 3, name: 'snowy', age: 5} ],
quacky: [ { id: 2, name: 'quacky' } ]
}
Then you can just do:
const expected = {
snowy: [ { id: 1, name: 'snowy' }, { id: 3, name: 'snowy', age: 5} ],
quacky: [ { id: 2, name: 'quacky' } ]
}
const res = arrangeBy(users,key)
expect(res).toEqual(expected)
But looking at your Error message I guess you have something else mixed up. In the beginning you listed the implementation of a sort function which seems to not be used in the test. Where is arrangeBy coming from now.
Please provide more code examples.

How do I exclude null values when merging objects by key?

Lets say I have an array of objects in Javascript:
id: 1,
name: 'Snowy',
},
{
id: 2,
name: 'Quacky',
age: 13
},
{
id: 3,
name: 'Snowy',
age: 1,
},
{
name: null
}
]
I have created a function to arrange them by a key:
const filter =
(pets, key) =>
_(pets)
.filter(pets => _.has(pets, key))
.groupBy(key)
.value()
Although, the output of this function when called persists the null entry:
{
Snowy: [ { id: 1, name: 'Snowy' }, { id: 3, name: 'Snowy', age: 1 } ],
Quacky: [ { id: 2, name: 'Quacky', age: 13 } ],
null: [ { name: null } ]
}
Is there I way I can filter out any of the null values here?
You could try by changing the method you use in in your predicate function from _.has to _.get.
So, instead of checking if a path/ key exist in an object, you instead check the value of a path/ key within an object it its null or not.
note: you might also want to check for falsy values here (such as undefined) instead of just null, since _.get returns undefined if the path/ key does not exist
const pets = [{
id: 1,
name: 'Snowy',
},
{
id: 2,
name: 'Quacky',
age: 13
},
{
id: 3,
name: 'Snowy',
age: 1,
},
{
name: null
}
];
const filter =
(pets, key) =>
_(pets)
.filter(pets => _.get(pets, key) !== null)
.groupBy(key)
.value();
console.log(filter(pets, 'name'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
Why not first filter the array for objects that have a truthy name? For example someArray.filter(a => a.name)...group()...

Rename result property in normalizr

Given data like:
{
id: 1,
ownerName: 'bob',
devices: [
{
id: 2
},
{
id: 3
}
]
}
how would I convert it to the following object
{
result: 1,
entities: {
owners: {
1: {
id: 1,
ownerName: 'bob',
deviceIds: [2, 3]
}
},
devices: {
2: {
id: 2
},
3: {
id: 3
}
}
}
}
using normalizr? I can't figure out how to change devices to deviceIds in the returned result...
You can use the Process Strategy for this. It allows you to manipulate your data before it is processed. Simply return a copy of your object with the keys changed from the processStrategy() method.
const Device = schema.Entity('devices');
const Owner = schema.Entity(
'owners',
{
deviceIds: [ Device ]
},
{
processStrategy: value => ({
id: value.id,
ownerName: value.ownerName,
deviceIds: value.devices
})
}
);

ReactJS - Swap out all the values in an array of objects in state with another array

I am trying to swap out all the values of an array of objects in state with a whole new array of objects. However, nothing seems to be working. I've tried the following:
const list1 = [
{ id: 1, name: 'item1' },
{ id: 2, name: 'item1' },
{ id: 3, name: 'item1' },
{ id: 4, name: 'item1' },
]
const list2 = [
{ id: 1, name: 'newItem1' },
{ id: 2, name: 'newItem2' },
{ id: 3, name: 'newItem3' },
{ id: 4, name: 'newItem4' },
]
class FindTab extends Component {
state = {
status: 'loading',
location: null,
view: this.props.view,
map: this.props.map,
locationValues: list1,
}
}
this.setState(prevState => ({
locationValues: [ ...prevState.locationValues, list2 ],
}))
or just simpler:
this.setState(locationValues: list2)
Neither seem to work. Is there any guidance as to how one should replace an array of objects with another array for a state property?
You could spread the array in a new one like:
const locationValues = [ ...state.locationValues, ...list2 ]
this.setState({ locationValues })

ES6 array of hashes return unique array of hashes [duplicate]

This question already has answers here:
Create array of unique objects by property
(17 answers)
Closed 3 years ago.
I have an object that looks like this:
const posts = [
{ id: 0, user: { id: 5564, name: 'john'} },
{ id: 1, user: { id: 5564, name: 'john'} },
{ id: 2, user: { id: 5560, name: 'jane'} }
]
I need an array of the unique user hashes like this:
[
{ id: 5564, name: 'john'},
{ id: 5560, name: 'jane'}
]
I'm able to retrieve all the users attributes from the posts array by doing:
const postUsers = posts.map(post => post.user)
which returns:
[
{ id: 5564, name: 'john'},
{ id: 5564, name: 'john'},
{ id: 5560, name: 'jane'}
]
where user john is listed twice
I've been able to get my desired result by doing:
const unique = {};
const uniqueUsers = [];
for(var i in postUsers){
if(typeof(unique[postUsers[i].id]) == "undefined"){
uniqueUsers.push(postUsers[i]);
}
unique[postUsers[i].id] = 0;
};
uniqueUsers
but there must be a cleaner way.
I've also been able to return the unique ids of all users by doing:
var ids = posts.map(post => post.user.id)
var uniqueIds = Array.from(new Set(ids)).sort();
which returns
[5564, 5560]
not sure if that helps. this article helped me a little https://medium.com/tomincode/removing-array-duplicates-in-es6-551721c7e53f
You could take a Map and get only the unique users.
const
posts = [{ id: 0, user: { id: 5564, name: 'john'} }, { id: 1, user: { id: 5564, name: 'john'} }, { id: 2, user: { id: 5560, name: 'jane'} }],
unique = Array.from(posts.reduce((m, { user }) => m.set(user.id, user), new Map).values());
console.log(unique);
If you don't mind using lodash you can do something like
const users = _map.(posts, 'user') // To get the list of users
_.uniqBy(users, 'id') // to get the uniq ones
Put the objects directly in uniqueUsers, then use Object.values() at the end to convert the object to an array.
const posts = [
{ id: 0, user: { id: 5564, name: 'john'} },
{ id: 1, user: { id: 5564, name: 'john'} },
{ id: 2, user: { id: 5560, name: 'jane'} }
];
let uniqueUsers = {};
posts.forEach(({user}) => uniqueUsers[user.id] = user);
uniqueUsers = Object.values(uniqueUsers);
console.log(uniqueUsers);
Use reduce to reduce the array by checking if the value is already in the array. If it is already in the array, return the current state of the array, otherwise add the item to the array.
const posts = [
{ id: 0, user: { id: 5564, name: 'john'} },
{ id: 1, user: { id: 5564, name: 'john'} },
{ id: 2, user: { id: 5560, name: 'jane'} }
]
const r = posts.map(i => i.user).reduce((acc, itm) => {
return !acc.find(i => i.id == itm.id) && acc.concat(itm) || acc
}, [])
console.log(r)

Categories

Resources