1

I have a initial state like this:

constructor(props) {
    super(props);

    this.state = this.getInitialState();

    this.setSqValue = this.setSqValue.bind(this);
}

getInitialState() {
    return {
        allSq: new Array(3).fill(new Array(3).fill(null))
    };
}

Then in a method like setSqValue (called by clicking a button) when I assign a new value to a cell, strangely all other cells with any position in first dimensional and same position in second dimensional will take that value!

The second problem is that the state is changed while I didn't call any setState!

setSqValue(i, j) {
    console.log(i, j);

    let {allSq} = this.state;

    let value = 'foo';

    console.log('before', allSq);

    allSq[i][j] = value;

    console.log('after', allSq);

//    this.setState({allSq});
}

The output in the console is this :

the output in the console

You can see the before and after values are same (why?!).

The state in the React developer tool:

the state in the react developer tool

Michał Perłakowski
  • 88,409
  • 26
  • 156
  • 177
Amir
  • 413
  • 4
  • 13

2 Answers2

3

In the chrome dev tools, objects aren't evaluated until you open them. Hover on the little icon to the right and you will see Object below was evaluated just now. . Try putting a debugger in there and I have a feeling you will see that your allSq in the before doesn't have foo in there. It seems as if everything is working correctly, you're just looking at the wrong things to see that.

Also, as another user said, .fill uses reference instead of value, so use .map instead.

larz
  • 5,724
  • 2
  • 11
  • 20
2

In JavaScript, Arrays are a special kind of Object, and if you pass an object to fill(), it uses the same object each time. You should use map() instead, which will create a copy of the array.

allSq: Array(3).fill().map(() => Array(3).fill(null))

To prevent the state from being changed you can use the Object.freeze() method:

allSq: Object.freeze(Array(3).fill().map(() => Object.freeze(Array(3).fill(null))))

With this, the line allSq[i][j] = value; will ether throw an error (in strict mode) or silently fail (outside of strict mode).

chris Frisina
  • 19,086
  • 22
  • 87
  • 167
Michał Perłakowski
  • 88,409
  • 26
  • 156
  • 177
  • Thanks. But still the second problem is there. Assigning to allSq is changing the state without setState. I can see it in the react developer tool. However the app behavior is like there is nothing happening. – Amir Sep 18 '18 at 17:25
  • 1
    @AmirhosseinDZ See my edit. The app behaves as if nothing happened because React doesn't monitor the state object for changes; it only updates the components if state was changed by the `setState` method. – Michał Perłakowski Sep 18 '18 at 17:35