title: React - Changing the state without using setState: Must avoid it?
body: <p><em>My code works, but I have a best practice question: I have an array of objects in the state, and a user interaction will change a value of one object at a time. As far as I know, I'm not supposed to change the state directly, i should always use <code>setState</code> instead. If I want to avoid that with any price, I will deep clone the array by iteration, and change the clone. Then set the state to the clone. In my opinion avoiding to change the state that I will change later anyway is just decreasing my performance.</em></p>
  
  <p><strong>Detailed version:</strong>
  this.state.data is an array of objects. It represents a list of topics in a forum, and a Favorite button will toggle, calling <code>clickCollect()</code>.
  Since I have an array in the state, when I change the is_collected property of one item, I need to create a copy of the array to work with, and after changing to the new value, I can set it to the state.  </p>
  
  <blockquote>
  <pre><code>var data = this.state.data.slice(0);
  data[index].is_collected = !data[index].is_collected;
  this.setState({data: data});
  </code></pre>
  </blockquote>
  
  <p><code>var data = this.state.data</code> : This would copy the pointer to the array and push(), shift(), etc would alter the state directly. Both <code>data</code> and <code>this.state.data</code> will be affected.</p>
  
  <p><code>var data = this.state.data.slice(0)</code> : This makes a shallow clone, push and shift doesn't change the state but in my clone I still have pointers to the elements of the state's array. So if I change <code>data[0].is_collected</code>, <code>this.state.data[0].is_collected</code> gets changed as well. This happens before I call <code>setState()</code>.</p>
  
  <p>Normally I should do:</p>
  
  <blockquote>
  <pre><code>var data = []; 
  for (var i in this.state.data) {
      data.push(this.state.data[i]); 
  }
  </code></pre>
  </blockquote>
  
  <p>Then I change the value at index, setting it to true when it's false or false when it's true:</p>
  
  <blockquote>
  <pre><code>data[index].is_collected = !data[index].is_collected;
  </code></pre>
  </blockquote>
  
  <p>And change state:</p>
  
  <blockquote>
  <pre><code>this.setState({data: data});
  </code></pre>
  </blockquote>
  
  <p>Consider my array is relatively big or enormously big, I guess this iteration will reduce the performance of my APP. I would pay that cost if I knew that it is the right way for any reason. However, in this function (<code>clickCollect</code>) I always set the new value to the state, I'm not waiting for a false API response that would say to stop making the change. In all cases, the new value will get into the state. Practically I call <code>setState</code> only for the UI to render again. So the questions are:</p>
  
  <ol>
  <li>Do I have to create the deep clone in this case? (<code>for var i in ...</code>)</li>
  <li>If not, does it make sense to make a shallow clone (<code>.slice(0)</code>) if my array contains objects? The changes are being made on the objects inside of the array, so the shallow clone still changes my state, just like a copy (<code>data = this.state.data</code>) would do. </li>
  </ol>
  
  <p>My code is simplified and API calls are cut out for simplicity.</p>
  
  <p>This is a beginner's question, so a totally different approach is also welcome. Or links to other Q &amp; A.</p>
  
  <blockquote>
  <pre><code>import React from 'react';
  
  var ForumList = React.createClass({
    render: function() {
        return &lt;div className="section-inner"&gt;
          {this.state.data.map(this.eachBox)}
        &lt;/div&gt;
    },
    eachBox: function(box, i) {
      return &lt;div key={i} className="box-door"&gt;
          &lt;div className={"favorite " + (box.is_collected ? "on" : "off")} onTouchStart={this.clickCollect.bind(null, i)}&gt;
            {box.id}
          &lt;/div&gt;
      &lt;/div&gt;
    },
    getInitialState: function() {
      return {data: [
        {
          id: 47,
          is_collected: false
        },
        {
          id: 23,
          is_collected: false
        },
        {
          id: 5,
          is_collected: true
        }
      ]};
    },
    clickCollect: function(index) {
      var data = this.state.data.slice(0);
      data[index].is_collected = !data[index].is_collected;
      this.setState({data: data});
    }
  });
  
  module.exports = ForumList;
  </code></pre>
  </blockquote>