title: How to determine JS bottlenecks in React Native code?
body: <p>I am adding a React Native <a href="http://facebook.github.io/react-native/docs/slider.html" rel="noreferrer">Slider</a> component to an existing app, and prefer to utilize its <code>onValueChange</code> prop so that as the user slides the knob left and right, a couple of Text components have their values updated in response to the Slider's current value.</p>
  
  <p>On a first attempt this causes a significant amount of lag after letting go of the slider knob. StackOverflow isn't letting me embed the gif here so I'll leave the link instead: <a href="https://imgur.com/sEowpZt" rel="noreferrer">http://imgur.com/sEowpZt</a></p>
  
  <p>When I comment out <code>onValueChange</code> and use <code>onSlidingComplete</code> instead, there is no lag at all, but the two text components will not have their values updated until the sliding stops, which reduces the effect. My suspicion is that the <code>setState</code> calls inside <code>onValueChange</code> are piling up at a faster rate than than at which they are being processed/completed and it has something to do with other parts of my app. To confirm this, I created a new react native app via <code>react-native init</code>, added that same <code>_renderNameYourPriceModal()</code> to the code, included a button on the screen to open it, and discovered there is no lag at all: <a href="https://imgur.com/iZnvDML" rel="noreferrer">http://imgur.com/iZnvDML</a></p>
  
  <p>How can I determine what is slowing down the <code>setState</code> calls for my existing app? I discovered the <a href="https://facebook.github.io/react/docs/perf.html" rel="noreferrer">React Perf tool</a> and am using it like this to print in the Chrome dev console a summary table.</p>
  
  <pre><code>import Perf from 'react-native/Libraries/Renderer/shims/ReactPerf'
  ...
    componentDidMount() {
      setTimeout(() =&gt; {
        Perf.start()
        setTimeout(() =&gt; {
          Perf.stop()
          const measurements = Perf.getLastMeasurements()
          Perf.printWasted(measurements)
        }, 7000)
      }, 1000)
    }
  </code></pre>
  
  <p>According to the Perf docs for <a href="https://facebook.github.io/react/docs/perf.html#printwasted" rel="noreferrer">printWasted</a>:</p>
  
  <blockquote>
    <p><strong>printWasted()</strong></p>
    
    <p><code>Perf.printWasted(measurements)</code></p>
    
    <p><strong>The most useful part of the profiler.</strong></p>
    
    <p>"Wasted" time is spent on components that didn't actually render
    anything, e.g. the render stayed the same, so the DOM wasn't touched.</p>
  </blockquote>
  
  <p>But I'm not sure how to interpret the results to make the necessary changes. For example, the first four rows of that table when running my app (which has 24 rows in total) looks like this:</p>
  
  <p><a href="https://i.stack.imgur.com/jk0Jh.png" rel="noreferrer"><img src="https://i.stack.imgur.com/jk0Jh.png" alt="Chrome Dev Tools console - printWasted() partial result"></a></p>
  
  <p>I don't know which View the first line, <code>"ItemDetailsScreen &gt; View"</code> inside the <code>Owner &gt; Component</code> column, is referring to because there are 20+ Views on that screen alone. For further context, I'm using React-Navigation and this is a nested screen inside a StackNavigator, although I don't see how updates to this screen's state could cause re-renders in screens further up the hierarchy. Is it necessary to break this screen down further into more custom sub-components so that I override <code>shouldComponentUpdate</code>, or so that the <code>printWasted</code> results tell exactly which areas are at fault?</p>
  
  <p>Here is the function I have for returning the Modal with the Slider inside:</p>
  
  <pre><code>  _renderNameYourPriceModal() {
      var likelihood = 'Possible'
      var lowestVal = 5
      var highestVal = 15
      if (this.state.nypValue &lt; 6) {
        likelihood = 'Nearly Impossible'
      } else if (this.state.nypValue &lt; 8) {
        likelihood = 'Highly Unlikely'
      } else if (this.state.nypValue &lt; 10) {
        likelihood = 'Unlikely'
      }
      return (
        &lt;Modal
          onRequestClose={() =&gt; { this.setState({nypModalVisible: false})}}
          animationType={"fade"}
          transparent={true}
          visible={this.state.nypModalVisible}&gt;
          &lt;View style={{paddingTop: 22, height: Dimensions.get('window').height, backgroundColor: 'rgba(252,84,102,0.9)', alignItems: 'center', justifyContent: 'center'}}&gt;
            &lt;View
              style={{
                height: Dimensions.get('window').height * 0.5,
                width: Dimensions.get('window').width * 0.9,
                backgroundColor: 'white',
                borderRadius: 10,
                alignItems: 'center'
              }}&gt;
              &lt;View
                style={{flex: 0.8, alignItems: 'center', justifyContent: 'center'}}&gt;
                &lt;View style={{flex: 0.25, flexDirection: 'row', width: Dimensions.get('window').width * 0.97, top: -10, alignItems: 'flex-start', justifyContent: 'center'}}&gt;
                  &lt;View style={{flex: 0.1}}&gt;&lt;/View&gt;
                  &lt;View style={{flex: 0.8, alignSelf: 'center', alignItems: 'center', justifyContent: 'center'}}&gt;
                    &lt;Text style={{fontSize: 23}}&gt;Name Your Price&lt;/Text&gt;
                  &lt;/View&gt;
                  &lt;View style={{flex: 0.1, top: -5, height: 40, alignItems: 'flex-end', justifyContent: 'flex-end'}}&gt;
                    &lt;TouchableHighlight
                      underlayColor={'gray'}
                      style={{height: 40, width: 40, backgroundColor: 'gray', borderRadius: 20, alignItems: 'center', justifyContent: 'center'}}
                      onPress={() =&gt; {
                        // close
                        this.setState({nypModalVisible: false})
                      }}&gt;
                      &lt;Text style={{fontSize: 25, color: 'white'}}&gt;X&lt;/Text&gt;
                    &lt;/TouchableHighlight&gt;
                  &lt;/View&gt;
                &lt;/View&gt;
                &lt;View style={{flex: 0.25, width: Dimensions.get('window').width * 0.8, alignItems: 'center', justifyContent: 'flex-start'}}&gt;
                  &lt;View style={{flex: 0.5, flexDirection: 'row', alignItems: 'center', justifyContent: 'center'}}&gt;
                    &lt;View style={{flex: 0.2, alignItems: 'center', justifyContent: 'center'}}&gt;
                      &lt;Text style={{fontSize: 19}}&gt;${lowestVal.toFixed(2)}&lt;/Text&gt;
                    &lt;/View&gt;
                    &lt;View style={{flex: 0.6, alignItems: 'center', justifyContent: 'center'}}&gt;
                      &lt;Slider
                        style={{width: Dimensions.get('window').width * 0.5}}
                        maximumValue={15}
                        minimumValue={5}
                        step={0.5}
                        value={this.state.nypValue}
                        // onSlidingComplete={(val) =&gt; {
                        //   this.setState({nypValue: val})
                        // }}
                        onValueChange={(val) =&gt; {
                          // change value here
                          this.setState({nypValue: val})
                        }}
                        /&gt;
                    &lt;/View&gt;
                    &lt;View style={{flex: 0.2, alignItems: 'center', justifyContent: 'center'}}&gt;
                      &lt;Text style={{fontSize: 19}}&gt;${highestVal.toFixed(2)}&lt;/Text&gt;
                    &lt;/View&gt;
                  &lt;/View&gt;
                  &lt;Text&gt;${this.state.nypValue.toFixed(2)}&lt;/Text&gt;
                  &lt;Text&gt;Likelihood: {likelihood}&lt;/Text&gt;
                &lt;/View&gt;
                &lt;View style={{flex: 0.5, paddingTop: 20, alignItems: 'center', justifyContent: 'flex-start', paddingHorizontal: 10}}&gt;
  
                  &lt;Text style={{textAlign: 'center', top: 25, fontSize: 18}}&gt;Let us know the price you'd like to see this item drop to, and we'll let YOU know when it does!&lt;/Text&gt;
                &lt;/View&gt;
              &lt;/View&gt;
              &lt;View style={{flex: 0.2, alignItems: 'center', justifyContent: 'center'}}&gt;
                &lt;TouchableHighlight
                  style={{height: 50, width: Dimensions.get('window').width * 0.8, alignItems: 'center', justifyContent: 'center', backgroundColor: '#70a8ff', borderRadius: 5}}
                  underlayColor={'#70a8ff'}
                  onPress={() =&gt; { }}&gt;
                  &lt;Text style={{fontSize: 20, color: 'white'}}&gt;Set Price Alert&lt;/Text&gt;
               &lt;/TouchableHighlight&gt;
              &lt;/View&gt;
            &lt;/View&gt;
          &lt;/View&gt;
        &lt;/Modal&gt;
      )
    }
  </code></pre>