0

I am running into really, really weird behavior with Redux. Basically I have a game with a static map where the player moves around on the map. The map and the player is represented by colored div's. That's all I'm trying to do and I was briefly able to get it working.

I create the movement by first getting the empty map (which is a hardcoded const array of arrays) and then adding the player's (new) position at the correct coordinates. Then I render it to the view layer in React. The outputted new map with the player's position is not named the same as the empty map.

However something very weird is happening with Redux where it is somehow changing the hardcoded const array of arrays when I render it. Putting in a ton of console.logs to see what is going on with the variables confirm that this is what is happening. Could someone please have a look at this codepen:

http://codepen.io/swyx/pen/MJbezj?editors=1010

and teach me how to trace what on earth is going on with my mutable const?

EDIT: here is the relevant code (constMap is a const array of arrays)

const InitMap = function() {
  console.log('InitMap')
  return constMap  /// why is this changing every single time???
}

this is later combined with the other reducers:

const rootReducer = combineReducers({
  gamemap: InitMap,
  user: InitUser,
  userMove: UserMove
});

and then used in the relevant mapStateToProps function:

function GMmapStateToProps(state){
  //from here goes into this.props
  console.log('GMmapStateToProps')
  console.log(state)
  console.log(constMap)
  var newgamemap = constMap, //state.gamemap also doesnt work,
      newuser = state.user
  console.log(newgamemap)
  if (state.userMove) {
    //check if is whitespace
    var x2 = newuser.location.x + state.userMove.vector.x
    var y2 = newuser.location.y + state.userMove.vector.y
    if (newgamemap[y2][x2] === 1) {
      newuser.location.x = x2
      newuser.location.y = y2
      //add user
      newgamemap[newuser.location.y][newuser.location.x] = 9
    }
  } else {    
    //add user
    newgamemap[newuser.location.y][newuser.location.x] = 9
  }
  console.log(newgamemap)
  return{
    xgamemap: newgamemap,
    user: newuser
  }
}

what is ridiculous is the value of constMap keeps changing every time i call this! why/how? it is making me question my sanity.

swyx
  • 2,378
  • 5
  • 24
  • 39
  • 2
    Only the array reference is a constant; the content is mutable. This is valid: `const a = [1,2,3]; a.splice(0,3);` but this is not: `const a = [1,2,3]; a = [];` Something is mutating your array, but the `const`-ness isn't going to get the runtime to help you find where it's being mutated. – cartant Jan 17 '17 at 20:53
  • hey @cartant, thanks for replying. i was worried this was going to be some weird pointer vs reference thing (i thought that was a C thing and not a javascript thing). is there a thing in chrome dev tools that can help me track the content of the array? – swyx Jan 17 '17 at 20:59
  • 2
    Now that you've added the code, it's clear you are mutating it in `GMmapStateToProps` with the changes your are making to `newgamemap` - which refers to the same array. You've tagged your question with `redux`, but you should not be mutating application state in a Redux architecture. – cartant Jan 17 '17 at 21:10

2 Answers2

1

That's because const does not create immutable. From MDN,

The const declaration creates a read-only reference to a value. It does not mean the value it holds is immutable, just that the variable identifier cannot be reassigned. For instance, in case the content is an object, this means the object itself can still be altered.

So the following is valid

const myArr = []
myArr.push(1)
myArr = [1,2,3] //throw error

const myObj = {}
myObj['test'] = true

If you need to, look into Object.freeze

S Ko
  • 11
  • 2
0

with @cartant's help - the problem here was that i didn't know that javascript passes arrays and objects by reference not by value. so of course by assigning my array a different name I wasn't doing anything to change the end result. and of course javascript doesnt have a native deep copy method because javascript. so i guess if future people run into this, just go the deep copy route: What is the most efficient way to deep clone an object in JavaScript?

Community
  • 1
  • 1
swyx
  • 2,378
  • 5
  • 24
  • 39