title: App crash when adding item to ListView
body: <p>I have a <code>ListView</code> that seems to crash on certain occasions when I'm adding an item to it.
  The worst thing about this crash is that I can't find consistent reproduction steps. It always happens upon having a new item added to the <code>ListView</code> but it only happens once for every ~10 item adds.</p>
  <p>I have a real-time client that keeps getting data added to it over time. When I have two devices showing the same data getting a new one together and one of them crashes, the other one crashes too for the same reason.</p>
  <p>This is the stacktrace and error:</p>
  <pre><code>    E/AndroidRuntime: FATAL EXCEPTION: main
      Process: {packagename}, PID: 28309
      java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
      at android.view.ViewGroup.addViewInner(ViewGroup.java:4309)
      at android.view.ViewGroup.addView(ViewGroup.java:4145)
      at android.view.ViewGroup.addView(ViewGroup.java:4086)
      at com.facebook.react.views.view.ReactViewManager.addView(ReactViewManager.java:203)
      at com.facebook.react.views.view.ReactViewManager.addView(ReactViewManager.java:37)
      at com.facebook.react.uimanager.NativeViewHierarchyManager.manageChildren(NativeViewHierarchyManager.java:394)
  </code></pre>
  <p>I couldn't find anyone with this issue in react-native that doesn't relate to his own native code. I didn't write any native code in this one.</p>
  <p>According to posts about this issue for native Android apps, it smells like the <code>ListView</code> somehow mishandling it's items and trying to add one before detaching it from a previous parent.</p>
  <p>Does anyone have ideas about what might cause it?
  Thanks.</p>
  <h3>Update:</h3>
  <p>Here's my code, it's longer than needed for the example but just in case it contains something weird I'm doing that causes this issue, I'm attaching the whole thing</p>
  <pre><code>class ItemsViewer extends Component {
      constructor() {
          super();
  
          this._isMounted = true;
          const dataSource = new ListView.DataSource({rowHasChanged: (r1, r2) =&gt; r1 !== r2});
          this.state = {
            dataSource: dataSource,
          };
  
          this._shouldAdjustScrollForKeyboardOnNextLayout = false;
  
          this._scrollListToBottomThrottled = throttle(this._scrollListToBottom.bind(this), 300);
          this._onListLayout = this._onListLayout.bind(this);
          this._onFooterLayout = this._onFooterLayout.bind(this);
          this._renderRow = this._renderRow.bind(this);
          this._renderFooter = this._renderFooter.bind(this);
      }
  
      componentWillUnmount() {
          this._isMounted = false;
      }
  
      componentWillMount() {
          this._isMounted = true;
          this.setState({dataSource: this.state.dataSource.cloneWithRows(this.props.items)});
      }
  
      componentWillReceiveProps(nextProps) {
          if (this.props.items != nextProps.items) {
              this.setState({dataSource: this.state.dataSource.cloneWithRows(nextProps.items)});
          }
  
          if(this.props.isKeyboardShown != nextProps.isKeyboardShown) {
              this._shouldAdjustScrollForKeyboardOnNextLayout = true;
          }
      }
  
      _scrollListToBottom() {
          if(!this._isMounted) return;
  
          if (this.listHeight &amp;&amp; this.footerY &amp;&amp; this.footerY &gt; this.listHeight) {
              var scrollTarget = this.listHeight - this.footerY;
              var scrollResponder = this.refs.itemsList.getScrollResponder();
  
              scrollResponder.scrollTo({y: -scrollTarget});
          }
      }
  
      _onScroll(event) {
          this.scrollY = event.nativeEvent.contentOffset.y;
      }
  
      _renderRow(rowData, sectionID, rowID) {
          let prevItem = null;
          if(this.props.items.length &gt; 1 &amp;&amp; rowID &gt; 0) {
              prevItem = this.props.items[rowID - 1];
          }
  
          return renderItem(getItemByContentType, rowData, prevItem, this.props.userColor);
      }
  
      _onListLayout(event) {
          this.prevListHeight = this.listHeight === undefined ? 0 : this.listHeight;
          this.listHeight = event.nativeEvent.layout.height;
  
          this._adjustScrollForKeyboardIfNeeded();
      }
  
      _adjustScrollForKeyboardIfNeeded() {
          if(!this._isMounted) return;
          
          if(!this._shouldAdjustScrollForKeyboardOnNextLayout) return;
          this._shouldAdjustScrollForKeyboardOnNextLayout = false;
  
          const diff = this.prevListHeight - this.listHeight;
          var scrollTarget = this.scrollY + diff;
          this.refs.itemsList.scrollTo({y: scrollTarget});
      }
  
      _onFooterLayout(event) {
          const prevY = this.footerY;
          this.footerY = event.nativeEvent.layout.y + event.nativeEvent.layout.height;
  
          // Scrolling to bottom when footer location has changed, indicating new items arrived
          if(this.footerY !== prevY) {
              this._scrollListToBottomThrottled();
          }
      }
  
      _renderFooter() {
          return &lt;View onLayout={this._onFooterLayout}
                       style={style.listFooter} /&gt;;
      }
  
      render() {
          const {dataSource} = this.state;
  
          return &lt;ListView dataSource={dataSource} enableEmptySections={true}
                           renderRow={this._renderRow}
                           ref='itemsList' initialListSize={50}
                           onLayout={this._onListLayout}
                           renderFooter={this._renderFooter}
                           onScroll={this._onScroll.bind(this)} /&gt;;
      }
  };
  </code></pre>