Copy an Object with Object.assign- Redux

Copy an Object with Object.assign- Redux
0

#1

Hey there can you help me with the code. Whenever I’m running the tests its showing that “Cannot assign to read only property ‘status’ of object ‘#’”
I can’t figure out what’s wrong.


const defaultState = {
  user: 'CamperBot',
  status: 'offline',
  friends: '732,982',
  community: 'freeCodeCamp'
};

const immutableReducer = (state = defaultState, action) => {
  switch(action.type) {
    case 'ONLINE':
      let newObj = state;
      return Object.assign(newObj, {status: action.type});
    default:
      return state;
  }
};

const wakeUp = () => {
  return {
    type: 'ONLINE'
  }
};

const store = Redux.createStore(immutableReducer);

Your browser information:

User Agent is: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36.

Link to the challenge:
https://learn.freecodecamp.org/front-end-libraries/redux/copy-an-object-with-object-assign


#2

let newObj = state; - this isn’t a new object, it’s just a reference to the original object. This isn’t specific to what your doing, it’s how JS works.

With Object.assign though, you can assign to a new object, so if you have Object.assign({}, {foo: 1, bar: 2}, {foo: 2}) (note the empty object there) it will merge the object on the right with the the next one, so {foo: 2} over {foo: 1, bar: 2}. That means there’s a new value for foo, so you get {foo: 2, bar: 2}. Then it takes that and merges it with the next one, which is an empty object (so you still end up with {foo: 2, bar: 2} in this example, but if either of the second or third objects had been references, the end result would have been a new object unconnected to them)

tl/dr if you want to create a new object with Object.assign, put an empty object in as the first argument, and it will merge any other objects you give into that new object. It’s what’s called a shallow copy.


#3

I did it as well but it isn’t working

const defaultState = {
  user: 'CamperBot',
  status: 'offline',
  friends: '732,982',
  community: 'freeCodeCamp'
};

const immutableReducer = (state = defaultState, action) => {
  switch(action.type) {
    case 'ONLINE':
      let newObj = Object.assign({}, {status: action.type});
      return newObj;
    default:
      return state;
  }
};

const wakeUp = () => {
  return {
    type: 'ONLINE'
  }
};

const store = Redux.createStore(immutableReducer);

#4

So, going from what I said, remenber that you merge right-to-left and you can pass as many objects as you like to assign.

What you’re meant to do is merge {status: 'online'} into your state. Then that merged object gets merged into the new, empty object {}.

At the minute, you’re just merging the {status: 'online'} into a new object, so that’s all you end up with.


#5

Object.assign will copy all the properties from source to target. Basically, after allocating all the properties to the new object, you need to change the status property of the new object to online.

You need to do something like this:
let newObj = Object.assign({},state);
newObj.status=‘online’;
return newObj;

It will not mutate the original state and changes the “status” property of the new object to online.

Happy Coding!!


#6

Just like you said, it does the work

const newObj = Object.assign({}, state ,  {status: 'online'})
return newObj;

#7

True.
It’s even cleaner if we just go:

return Object.assign({}, state, {status: 'online'});

#8

Since we have been given an action, we ought to use that instead of hard coding “online”. I guess the most accurate solution would be:

return Object.assign({}, state, {status: action.type.toLowerCase()});


#9

As others have pointed it out, let newObj = state; won’t copy state to newObj. This is reference assign, not value. So whatever you do to newObj will have impact on state.

My first solution was copy state to some new object, then modify the status property of that new object. Finally, return the new object. But that’s a 3 lines of code:

const newState = Object.assign({}, state);
newState.status = 'online';
return newState;

There’s another way to do this with just one concise line. As the assign() method can take more than 2 arguments, here’s how you can do this with explanation:

return Object.assign({}, state, { status: 'online' });

The first argument, {}, is the initial look of the new object. state is the whole object we want to copy. So if we stop at this point, our new object is an exact copy of the state with just same properties and values.

However, you can provide a third argument as a object with property status as the only one property. This property will override the status property of the new object, making its value to be ‘online’.

I believe we should know and understand all the techniques manipulating object and array if we want to advance further.

Hope that makes sense to you.