title: React Native - ListView Scroll To Nested Child Ref?
body: <p>I am using <code>ListView</code> to display a list of <code>comments</code> and possibly <code>subcomments</code> if they exist on a comment. I'm trying to scroll to a specific <code>subcomment</code> via its <code>ref</code>, but I am not able to get it to work. I used 3 components (boiled down below) to accomplish this:</p>
  
  <p><strong>1. Comments</strong></p>
  
  <pre><code>import React, { Component } from 'react'
  import { TouchableOpacity, ListView, View, Text } from 'react-native'
  import CommentRow from './commentRow'
  
  const ds = new ListView.DataSource({ rowHasChanged: ( r1, r2 ) =&gt; r1.id !== r2.id });
  const commentsDataSource = [
    {id: '1', body: 'comment 1'},{id: '2', body: 'comment 2'},{id: '3', body: 'comment 3'},{id: '4', body: 'comment 4'},{id: '5', body: 'comment 5'},{id: '6', body: 'comment 6'},{id: '7', body: 'comment 7'},{id: '8', body: 'comment 8'},{id: '9', body: 'comment 9'},{id: '10', body: 'comment 10'},
    {id: '11', body: 'comment 11'},{id: '12', body: 'comment 12', hasSubComments: true},{id: '13', body: 'comment 13'},{id: '14', body: 'comment 14'},{id: '15', body: 'comment 15'},{id: '16', body: 'comment 16'},{id: '17', body: 'comment 17'},{id: '18', body: 'comment 18'},{id: '19', body: 'comment 19'},{id: '20', body: 'comment 20'}
  ];
  
  export default class Comments extends Component {
      constructor(props) {
        super(props);
  
        this.state = {
          dataSource: ds.cloneWithRows(commentsDataSource)
        };
      }
  
      scrollToSubCommentRef(ref) {
        this.rowz[ref].measure((ox, oy, width, height, px, py) =&gt; {
          const offsetY = oy;
          this.refs.mainListView.scrollTo({ y: offsetY })
        });
      }
  
      render() {
        return (
          &lt;View&gt;
              &lt;TouchableOpacity style={{backgroundColor: 'red', padding: 50}}
                                onPress={() =&gt; this.scrollToSubCommentRef('subComment_10')}&gt;
                  &lt;Text&gt;Scroll to subComment_10!&lt;/Text&gt;
              &lt;/TouchableOpacity&gt;
  
              &lt;ListView ref="mainListView"
                        renderRow={comment =&gt; &lt;CommentRow comment={comment} /&gt;}
                        dataSource={this.state.dataSource}
                        enableEmptySections={true} /&gt;
          &lt;/View&gt;
        )
      }
  }
  </code></pre>
  
  <p><strong>2. CommentRow</strong></p>
  
  <pre><code>import React, { Component } from 'react';
  import { View } from 'react-native'
  import CommentListItem from './commentListItem'
  
  export default class CommentRow extends Component {
      render() {
        const comment = this.props.comment;
  
        return (
          &lt;View key={`comment_${comment.id}`} style={{overflow: 'hidden'}}&gt;
            &lt;CommentListItem comment={comment} /&gt;
          &lt;/View&gt;
        )
      }
  }
  </code></pre>
  
  <p><strong>3. CommentListItem</strong></p>
  
  <pre><code>import React, { Component } from 'react'
  import { View, Text } from 'react-native'
  
  const subComments = [
    {id: '1', body: 'subcomment 1'},{id: '2', body: 'subcomment 2'},{id: '3', body: 'subcomment 3'},{id: '4', body: 'subcomment 4'},{id: '5', body: 'subcomment 5'},{id: '6', body: 'subcomment 6'},{id: '7', body: 'subcomment 7'},{id: '8', body: 'subcomment 8'},{id: '9', body: 'subcomment 9'},{id: '10', body: 'subcomment 10'},
    {id: '11', body: 'subcomment 11'},{id: '12', body: 'subcomment 12'},{id: '13', body: 'subcomment 13'},{id: '14', body: 'subcomment 14'},{id: '15', body: 'subcomment 15'},{id: '16', body: 'subcomment 16'},{id: '17', body: 'subcomment 17'},{id: '18', body: 'subcomment 18'},{id: '19', body: 'subcomment 19'},{id: '20', body: 'subcomment 20'},
    {id: '21', body: 'subcomment 21'},{id: '22', body: 'subcomment 22'},{id: '23', body: 'subcomment 23'},{id: '24', body: 'subcomment 24'},{id: '25', body: 'subcomment 25'},{id: '26', body: 'subcomment 26'},{id: '27', body: 'subcomment 27'},{id: '28', body: 'subcomment 28'},{id: '29', body: 'subcomment 29'},{id: '30', body: 'subcomment 30'},
    {id: '31', body: 'subcomment 31'},{id: '32', body: 'subcomment 32'},{id: '33', body: 'subcomment 33'},{id: '34', body: 'subcomment 34'},{id: '35', body: 'subcomment 35'},{id: '36', body: 'subcomment 36'},{id: '37', body: 'subcomment 37'},{id: '38', body: 'subcomment 38'},{id: '39', body: 'subcomment 39'},{id: '40', body: 'subcomment 40'},
    {id: '41', body: 'subcomment 41'},{id: '42', body: 'subcomment 42'},{id: '43', body: 'subcomment 43'},{id: '44', body: 'subcomment 44'},{id: '45', body: 'subcomment 45'},{id: '46', body: 'subcomment 46'},{id: '47', body: 'subcomment 47'},{id: '48', body: 'subcomment 48'},{id: '49', body: 'subcomment 49'},{id: '50', body: 'subcomment 50'},
    {id: '51', body: 'subcomment 51'},{id: '52', body: 'subcomment 52'},{id: '53', body: 'subcomment 53'},{id: '54', body: 'subcomment 54'},{id: '55', body: 'subcomment 55'},{id: '56', body: 'subcomment 56'},{id: '57', body: 'subcomment 57'},{id: '58', body: 'subcomment 58'},{id: '59', body: 'subcomment 59'},{id: '60', body: 'subcomment 60'},
    {id: '61', body: 'subcomment 61'},{id: '62', body: 'subcomment 62'},{id: '63', body: 'subcomment 63'},{id: '64', body: 'subcomment 64'},{id: '65', body: 'subcomment 65'},{id: '66', body: 'subcomment 66'},{id: '67', body: 'subcomment 67'},{id: '68', body: 'subcomment 68'},{id: '69', body: 'subcomment 69'},{id: '70', body: 'subcomment 70'}
  ];
  
  export default class CommentListItem extends Component {
    rowz = []; // to hold subComment refs for scroll access
  
    subCommentsList = () =&gt; {
      return subComments.map((subComment, i) =&gt; {
        return (
          &lt;View ref={i =&gt; this.rowz["subComment_"+subComment.id] = i} key={"subComment_"+subComment.id}&gt;
            &lt;Text&gt;{subComment.body}&lt;/Text&gt;
          &lt;/View&gt;
        );
      });
    }
  
    render() {
      const comment = this.props.comment;
  
      return (
        &lt;View&gt;
          &lt;Text&gt;{comment.body}&lt;/Text&gt;
          {comment.hasSubComments &amp;&amp; this.subCommentsList()}
        &lt;/View&gt;
      )
    }
  }
  </code></pre>
  
  <p>In the parent component <strong>#1</strong> I tried to scroll to a <code>subComment</code> via its <code>ref</code> of <code>subComment_10</code>, but measure gives an undefined error. I understand <code>this.rowz</code> doesn't exist in <code>#1</code> just in <code>#3</code> where the <code>subComments</code> map iterates over each <code>subComment</code> and assigns it to the <code>rowz</code> array (I just realized it does not assign the <code>subComment_idhere</code> to the <code>rowz</code> array for some reason).</p>
  
  <p>So how can we fix the <code>ref</code> assignment issue in the <code>#3</code> map so the <code>rowz</code> array gets a list of all the subComment <code>refs</code> so we can scroll to them? And how can we get the <code>TouchableOpacity</code> with <code>this.scrollToSubCommentRef('subComment_10')</code> in <strong>#1</strong> to scroll the <code>mainListView</code> to <code>subComment_10</code>?</p>
  
  <p><strong>UPDATE</strong></p>
  
  <p>With the provided solution, the <code>ref</code> is passed to the <code>rowz</code> array successfully, but as you'll notice, it does not scroll to <code>subComment_10</code>, instead it scrolls to the bottom of <code>comment 10</code>. It should scroll to the top of <code>subComment_10</code> so that it is the top most visible <code>subComment</code> on click of the <code>TouchableHighlight</code>:</p>
  
  <p><a href="https://i.stack.imgur.com/X8ivm.gif" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/X8ivm.gif" alt="enter image description here"></a></p>