how to avoid immutation in redux - javascript

I have a problem with a mutation I can't understand, here is my code :
const copyItems = Object.assign({}, state.items);
for(const typeItems of Object.values(copyItems[0])){
for(let items of typeItems){
if(items.id === action.item.id){
Object.assign(items, action.item);
}
}
}
return state.items;
I also tried by using const copyItems = state.items.slice().map(o => ({...o}) but even by returning the state the value is modified. Why?

Your state.items is a nested object. Then you can do these ways:
const newObj = JSON.parse(JSON.stringify(obj))
follow this link
or you can use lodash
const newObj = _.cloneDeep(obj)

Your copyItems copies the state.items that would have the same reference.
const copyItems = Object.assign({}, state.items);
Then you are mutating the state.items when you do the following.
Object.assign(items, action.item);
The answer from #bird may work but you will into problem with if you have circular structure or if the object has references to other objects then you will lose all those references. But it really depends on what you are trying to achieve.
Using Object.assign seems dangerous in terms of functional programming required by Redux. Should be fine if you use it on empty object (Object.assign({}, ...)) but not on an existing object.
I have an example code below that might help you case.
const state = {items:[{id:0,value:"default"},{id:1,value:"default"}]};
const action = {item:{id:0,value:"new"}};
const copyItems = state.items.map(o => o.id === action.item.id ? action.item : o);
console.log(state.items, copyItems);

Related

how can i check if an array of objects contains a key which is in array of strings js?

We have an array of objects like
const arr = [{id: "someId", name: {...}}, ...];
const skippedKeys = ["id"...]
How can i filtered the array of object based on skipped keys?
The result should be:
const result = [{name: {...}}, ...];
Also i don't want to make a cycle inside the cycle.
the result also could be implemented using lodash library.
we should remove key with value as well.
Since you stated that it could be implemented using lodash, here is some code using lodash:
let result = _.map(arr, (el)=> _.omit(el, skippedKeys))
const result = arr.map(obj =>
Object.keys(obj).reduce(
(res, key) => (
skippedKeys.includes(key) ? res : {...res, [key]: obj[key]}
),
{},
));
It's simple and no need for any nested cycles. There are two option to do that
Using includes function
const result = arr.filter((item) => !result.includes(item.id));
Using set
const dataSet = new Set(skippedKeys);
const result = arr.filter((item) => !dataSet.has(item.id));
I prefer the second one as it excludes double checks. Hope the answer was helpful.

How to prevent my array to updated again and again on onChange Function in React JS?

I have cloned an array and I have an onChange function. On calling onChange function my original and cloned array is updating according to the updated onChange value. But I don't want to update my cloned array. How can I do this ?
My code -
const clonedArray = [...originalArray];
const onChange = (id:number, value: string): void => {
const arrayData = originalArray;
const selectedData = arrayData.find(
(data) => data.myId === id
);
if (selectedData) {
// updating my originalArray according to new changed value;
}
}
this onChange function is also updating my clonedArray. I don't wanna update my clonedArray. How can I do this ? What is the solution useMemo or something ? Can anyone tell me the solution for it ?
Issue
This issue is state object/array mutation. You are mutating elements in an array and seeing the mutations manifest in a "copy".
Firstly, const clonedArray = [...originalArray]; is only a shallow copy of the originalArray, not a clone. This means that other than the array reference itself, all the elements in clonedArray still refer to the same elements in originalArray.
Secondly, if later you are making changes in originalArray and you are seeing them manifest in clonedArray then you are definitely mutating the element references instead of creating new references.
Solution
You are looking for the Immutable Update Pattern. When updating state in React it is necessary to shallow copy not only the root object/array that is being updated, but all nested state as well. To help with endeavor, especially when updating arrays, you will want to also use functional state updates so you can correctly update from the previous state.
For this I'm assuming (based on a comment that originalArray was in state) that your state looks something like this:
const [originalArray, setOriginalArray] = useState([]);
The change handler/state update (just an example since I don't know your exact update requirements)
const onChange = (id: number, value: string): void => {
const selectedData = originalArray.find((data) => data.myId === id);
if (selectedData) {
// updating my originalArray according to new changed value
// Array.prototype.map shallow copies the array into a new array reference
setOriginalArray(originalArray => originalArray.map(data => data.myId === id
? { // <-- updating element into new object reference
...data, // <-- shallow copy previous data element
property: value // <-- update property with new value
}
: data // <-- not updating, pass previous object through
);
}
}
Once you are correctly updating the array elements, then no mutations will occur to anything that may also be referencing the state.
you can use useMemo with empty dependency array. whenever originalArray updates, clonedArray doesn't change.
import { useMemo, useState } from "react";
const arr = [1,2,3]
export default function App() {
const [originalArray, setOriginalArray] = useState(arr)
const clonedArray = useMemo(() => originalArray, [])
return (
<div className="App" style={{textAlign:'center'}}>
originalArray: {originalArray}
<br/>
clonedArray:{clonedArray}
<br/>
<button onClick={() => setOriginalArray([1])}>update original</button>
</div>
);
}

React add array to state array

I am new to React. In my state, I am trying to have an empty array initialized to store polygons.
The structure I want to have is an array like this.state.polyList = [[dot1,dot2,dot3...],[dot1,dot2,dot3...]]
I am trying to have a
let newState = Object.assign({},this.state);
let newValue = [points]; // "points" is [dot1,dot2,dot3...]
console.log(newValue[0][0]); // able to print correctly
newState.polyList = newState.polyList.concat(newValue)
this.setState(newState)
However, when I later log the state.polyList, I only have a few empty array ([]) inside list
You can add like this array to state array
state = {
items: [4,5,6],
};
function to add
handleClick = e => {
this.setState({
items:[...this.state.items,[Math.floor(Math.random()*100),7,8]]
})
};
Change to something like below.
let newValue = [points]; // "points" is [dot1,dot2,dot3...]
console.log(newValue[0][0]); // able to print correctly
let newState = { ...this.state,
polyList: [...this.state.polyList, newValue] };
this.setState(newState)
Deep cloning in react doesn't work the way you are doing. A way that i prefer to use is by spread operator. You can do something like:
let newState = [...this.state.polyList];
newState.push(points)
this.setState({ polyList: newState });
Hope this works for you.
Best way to do this would be is structuring.
let oldState = [1,2,4]
this.setState ([...oldState, [new state array]])

Point-free Function Composition with Ramda.js

I am using Ramda.js for selector functions, to access data in a Redux store. What I want is to define my selectors as functions not referencing the state that the selectors act on, like:
const getUserName = path(['user', 'name']);
const name = getUserName({
user: {
name: 'Some Name'
}
});
This is easy for simple selectors, but sometimes becomes a problem for composed selectors.
Here is an example, where some items needs to be resolved, referenced by their id on an object:
const getItemById = id => state => path(['items', id], state);
const getConnectedItemIds = obj => path(['items'], obj);
const getItemsFromObj = obj => state => {
const ids = getConnectedItemIds(obj);
return ids.map(id => getItemById(id)(state));
};
The first function can easily be expressed without reference to state, and the second function without obj, something I believe is called point-free style. But how to write the third function without state?
I am looking for how to rewrite the third function using Ramda, but also rules and procedures regarding this, such as (without knowing if its true):
All composed functions need to have state as their last argument to be able to pull it out in the final composition.
There are many good suggestions already here. Probably most important is the advice to use point-free only when it improves readability, and not as a goal on its own.
My answer does use a point-free version of your main function and of one of your helpers, but skips it for the other, where I think readability would suffer.
const getItemById = id => path(['items', id]);
const getConnectedItemIds = prop ('items');
const getItemsFromObj = pipe (
getConnectedItemIds,
map (getItemById),
juxt
)
const obj = {foo: 42, items: ['8', '17']}
const state = {bar: 1, items: {'6': 'a', '8': 'b', '14': 'c', '17': 'd', '25': 'e'}}
console .log (
getItemsFromObj (obj) (state)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>const {juxt, map, path, pipe, prop} = R </script>
The important function here is juxt, which applies an array of functions to the same values, returning an array of the results.
Here getItemById is simplified from the original, by removing the state point, but making this point-free can be done only at a cost in readability, as far as I can tell. Other had suggestions for this, all of which are fine, but as they pointed out, none were as readable as the above. My version looked like this:
const getItemById = compose (path, flip (append) (['items']));
// or pipe (flip (append) (['items']), path);
I don't think it's any better or worse than the suggestions in the other answers, but none of them is as easy to read as
const getItemById = id => path(['items', id]);
Finally, if those helper functions are not used elsewhere, I think it can actually improve readability to inline them:
const getItemsFromObj = pipe (
prop ('items'),
map (id => path(['items', id])),
juxt
)
Note, although I didn't use it here, I really do like customcommander's suggestion of propOr([], 'items') for getConnectedItemIds. It cleanly removes one potential point of failure.
I do like pointfree style. I think it forces you to think twice about the design of your functions, which is always a good thing. However it should never be a goal. Use it only when it makes sense.
This function is already good enough:
const getItemById = id => state => path(['items', id], state);
My only suggestion would be to use curry:
const getItemById = curry((id, state) => path(['items', id], state));
You could convert it into pointfree style though, but I don't think it's actually worth it:
const getItemById = useWith(path, [pair('items'), identity]);
Let's go back to your question.
We have these two functions:
const getItemById = curry((id, state) => path(['items', id], state));
const getConnectedItemIds = propOr([], 'items');
You could design a getItemsFromObj pointfree style like this:
const getItemsFromObj = useWith(flip(map), [getConnectedItemIds, flip(getItemById)]);
Or you could also simply do:
const getItemsFromObj = curry((obj, state) => {
const ids = getConnectedItemIds(obj);
const idFn = flip(getItemById)(state);
return map(idFn, ids);
});
Which version would I recommend? I don't know; here's a couple of ideas to think about:
Does it feel natural to you?
What's your team affinity with FP? Can you train them? Go easy if they're just starting
In six months, which version would you feel more comfortable dealing with?
One thing I'd suggest though is that you get familiar with the
Hindley-Milner type system. It's definitely time well invested.
Don't let anybody tell you that you're not doing functional programming correctly if you're not doing it pointfree style.
I think you could still write it in a point-free fashion,
readability, however, gets a bit compromised..
Hope it helps :)
/**
* #param {string} id
* #param {Object<string, *>} state
**/
const getItemById = R.useWith(R.prop, [
R.identity,
R.prop('items'),
]);
const getItemsFromObj = R.useWith(R.flip(R.map), [
R.pipe(R.prop('items'), R.map(getItemById)),
R.applyTo,
]);
const items = {
1: { id: 1, title: 'Hello World' },
2: { id: 2, title: 'Hello Galaxy' },
3: { id: 3, title: 'Hello Universe' },
};
const state = { items };
// this should only take 'world' and 'universe';
console.log(
'result',
getItemsFromObj({ items: [1, 3] }, state),
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js" integrity="sha256-xB25ljGZ7K2VXnq087unEnoVhvTosWWtqXB4tAtZmHU=" crossorigin="anonymous"></script>
Notes:
Ramda functions are all curried, so you do not need to declare arguments in tail position: obj => path(['items'], obj); is equal to path(['items']);
Being point-free helps to write small and focussed functions, but it should be balanced with composition readability
It's possible to make it both short and point free, but I'm not sure if it's more readable than the a function using variables.
const getItemsFromObj = R.useWith(R.props, [R.prop('items'), R.prop('items')])
I'm not using your getItemById here, since this case is ideal for R.props instead. If you really want to use both of your original functions, you could write it like this.
const getItemsFromObj = R.useWith(
R.flip(R.map), [getConnectedItemIds, R.flip(R.uncurryN(2, getItemById))]
)
The flip and uncurry is needed to reverse the getItemById function arguments from id -> state -> value into state -> id -> value

How can I improve my filtered Loop of Objects with lodash?

I am looping through issues in the data filtered by a condition.
const rowObjects = Object.keys(data).filter((list) => {
let issueRow = data[list];
let destroyFilter = list._destroy:
return !destroyFilter ? list : null;
}).
map((issue, key) => ({
console.log(key + 1)
}));
I am wondering if there is a way todo this with lodash?
I would do something like this, I just learned actually.
const filter = _.pickBy(data, (list) => {
return //whatever you want
});
Looking at your code, from what I can gather you have your data as an object literal, you then mark the key's you don't want with a _destroy tag.
You then want another object literal without the one's marked _destroy.
Below is a version that does that without lodash,.
There might be an easier way in lodash, not sure. But the ES6 way to me just looks so natural, and easy to follow. It could even be made to look simpler by splitting out bits into utility functions, eg. the last reduce could be used in other places were you want key / value, transformed back into an object literal.
ps. If you don't mind modifying the original object literal, this is even easier, and most likely better performance. Things like React I believe like deterministic data, so deleting in-place might not be an option.
const data = {
a: {
_destroy: true,
value: "destroy this"
},
b: {
value: "Keep Me!!"
}
};
const data2 =
Object.entries(data).
filter(([key, value]) => !value._destroy).
reduce((obj, [key, value]) => (obj[key] = value) && obj, {});
console.log(data2);

Categories