Am i Mutating redux state with this function ?
function addDefinition(object, payload) {
var newObject = Object.assign({}, object);
if(!newObject[payload.guid]){
newObject[payload.guid] = [];
}
newObject[payload.guid].push(payload);
return newObject;
}
I want to create structure to hold data related to different part of application.
Yes, that .push() statement is mutating in the later calls. In the first call, the array is newly created, so it doesn't qualify as a mutation. In a later call, you've created a new object but copied the existing array reference, so .push() mutates the existing array.
Yes. See markerikson's answer. Keep in mind you could avoid this with the spread operator.
const INITIAL_STATE = {
guid: []
}
function addDefinition(state = INITIAL_STATE, payload) {
return {...state, guid: [...state.guid, payload]};
}
In addition you could avoid the if statement with initial state.
Related
I read the official Vuex example of how to mutate the state of element in array of objects data.
editTodo (state, { todo, text = todo.text, done = todo.done }) {
const index = state.todos.indexOf(todo)
state.todos.splice(index, 1, {
...todo,
text,
done
})
}
It seems a bit an overkill to find the index first (first loop), perform a splice and perform a copy with spread operator ...todo (would it be considered a second loop?).
Going by the docs:
When adding new properties to an Object, you should either:
Use Vue.set(obj, 'newProp', 123), or Replace that Object with a fresh one. For example, using the object spread syntax: state.obj = { ...state.obj, newProp: 123 }
There are only two ways to set / update properties to object.
In bigger data scenario that is causing some performance issues. Is there any better (more efficient) way to update an element in array of objects?
I'm still new to react and I still don't really understand about mutated the state.
I have seen many posts about this but I do not understand how the mutation process happened so I think it is necessary to ask this.
First i need to know is this called mutated state?
this.setState(prevState=>({
colors:this.state.colors.map((c,i)=>{
return{
original_color:c.original_color,
hex_color:c.hex_color,
isActive:false
}
})
}))
OR
let newData = this.state.colors.map((c,i)=>{
return{
original_color:c.original_color,
hex_color:c.hex_color,
isActive:false
}
})
this.setState({
colors: newData
})
in this case i just want to set all of this value isActive to false
Last
i want to set this value to empty
this.setState({
colors:[]
})
Since .map() returns a new array as a result, using it is safe and is not considered a mutation.
Basically, anything that doesn't change the original state or any direct references to it, is not considered a mutation.
Your state is not mutated in any case. .map() returns a new array. Your state is only mutated when you directly assign it to another value without calling .setState() like so:
this.state.value = anotherValue;
Or:
this.state.value.push(anotherValue)
I know you can copy an array with the spread operator:
const itemsArr = [...this.state.itemsArr];
and you can destructure an array that's an object key's value:
const { itemsArr } = this.state
Is there a way to combine them into one step? Pseudocode:
const { itemsArr } = [...this.state]
or
const { [...itemsArr] } = this.state
EDIT: Is there a way to combine them into one step, so as to avoid typing "itemsArr" twice?
It can be done by destructuring itemsArr from a copy of state:
const { itemsArr } = JSON.parse(JSON.stringify(this.state))
The strong point of this is that your nested objects are cloned, so your state.itemsArr is copied too and modifying itemsArr won't change the array in state.
The disadvantage is that if your state object contains functions, they won't be accessible using this method plus you can question the performance.
Another way to copy state is by using Object.assign:
const { itemsArr } = Object.assign({}, this.state)
With this you can access your functions inside of state but it makes a shallow copy, so state.itemsArr won't be cloned.
ECMAScript2018 actually has a spread operator that works with JSON objects:
const { itemsArr } = { ...this.state }
https://codesandbox.io/s/32qvzjy2op (look at your browser's console, the one in the tool is bad).
But then again, it only makes a shallow copy.
The best way would be to write/import a deepCopy function that clones the object with it's nested properties and functions.
https://lodash.com/docs#cloneDeep
This is reducer_posts.js from very simple blog react-redux app.
import _ from 'lodash';
import { FETCH_POSTS, FETCH_ONE_POST, DELETE_POST } from '../actions/index';
export default function (state = {}, action) {
switch (action.type) {
case DELETE_POST:
return _.omit(state, action.payload);
case FETCH_ONE_POST:
return { ...state, [action.payload.data._id]: action.payload.data };
case FETCH_POSTS:
return _.mapKeys(action.payload.data, '_id');
default:
return state;
}
}
_.omit(state, action.payload) is returning state without action.payload, so it is returning state without deleted post.
_.mapKeys(action.payload.data, '_id') creates an object with the same values as initial object, but new object has new key taken from action.payload.data._id
But I can't just get what in that code, this piece of syntax exactly does:
return { ...state, [action.payload.data._id]: action.payload.data };
What does this line of code do? What does ... mean?
What does this line of code do?
Basically it does two things:
Adds old state properties to the new object by copying all enumerable properties from the state to the {}. Here is the quote form here:
An alternative approach is to use the object spread syntax proposed
for the next versions of JavaScript which lets you use the spread
(...) operator to copy enumerable properties from one object to
another in a more succinct way. The object spread operator is
conceptually similar to the ES6 array spread operator.
Creates a new computed property with the key that is the result of evaluating action.payload.data._id and sets its value to the result of evaluating action.payload.data. Here is the quote from here:
Starting with ECMAScript 2015, the object initializer syntax also
supports computed property names. That allows you to put an expression
in brackets [], that will be computed as the property name. This is
symmetrical to the bracket notation of the property accessor syntax,
which you might have used to read and set properties already.
Here is the example in pure JS:
const action = {payload: {data: {_id: 'some'}}};
const oldState = {a: '3'};
const newState = {...oldState, [action.payload.data._id]: action.payload.data}
console.log(newState); // {a: '3', some: {_id: 'some'}}
This line creates a brand new object based on all the available properties of current state and only updates the "action.payload.data._id" parameter.
as an example: When Redux is used as the application state management paradigm, to notify Redux about any changes in states, a new state object (reducer output) should be created to ensure the Redux that there is an actual state change occurred, (therefor the component will be re-rendered)
I'm trying to learn Redux as well as es7 from here and have trouble understanding the author's point below about the following code:
Note also that this ES7 Object Spread notation suits our example
because it's doing a shallow copy of { message: action.value
} over our state (meaning that first level properties of state
are completely overwritten - as opposed to gracefully merged - by
first level property of { message: action.value }).
var reducer_3 = function (state = {}, action) {
console.log('reducer_3 was called with state', state, 'and action', action)
switch (action.type) {
case 'SAY_SOMETHING':
return {
...state,
message: action.value
}
default:
return state;
}
}
How is the first level properties of state overwritten by {message: action.value} when the author's use of Object Spread notation simply adds the message: action.value key/value pair to the original state? The first level of properties of state are still there because of the Object Spread notation right? Thus, if the original state was {a:"foo", b:"bar"} the new state after dispatching an action of SAY_SOMETHING would be {a:"foo", b:"bar", message: 'SAY_SOMETHING}, correct? Nothing was replaced.
It will only override IFF it is replacing an existing property. So, your example is exactly correct. The author mentioned that it would do a shallow merge, which would override existing keys, but gave an example that simply added a property as you said. Maybe send a PR to clarify :)
When using the spread operator to create a new object, it behaves exactly like Object.assign or _.extend in Underscore/Lo-dash with an empty object literal as the first argument. So, these are all equivalent...
Object.assign({}, a, b)
_.extend({}, a, b)
{ ...a, ...b }
As you can see in the Babel REPL, Babel simply converts this syntax to Object.assign, if its available, or a polyfill of Object.assign