Shopify / react-native-performance

Performance monitoring for React Native apps
https://shopify.github.io/react-native-performance
MIT License
916 stars 44 forks source link

Attempting to measure re-rending times causes an exception. #159

Open GiridharKarnik opened 1 year ago

GiridharKarnik commented 1 year ago

Current behavior

Attempting to measure re-rending times causes an exception.

Expected behavior

The library should be able to measure re-render times as advised in https://shopify.github.io/react-native-performance/docs/fundamentals/measuring-render-times.

To Reproduce

Here is the repro https://github.com/GiridharKarnik/RerenderFlow.

Platform:

Packages

Which packages are affected by the issue?

Environment

The package versions can be referred from the repo link pasted above.

package version
@shopify/react-native-performance 4.1.2
@shopify/react-native-performance-lists-profiler -
flipper-plugin-shopify-react-native-performance -
@shopify/react-native-performance-navigation -
@shopify/react-native-performance-navigation-bottom-tabs -
@shopify/react-native-performance-navigation-drawer -
@react-navigation/native -
@react-navigation/bottom-tabs -
@react-navigation/drawer -
@react-navigation/stack -
react-native 0.72.4

Additional info

The app contains a straightforward screen with a button that increments a state, triggering a re-render. The root of the App is wrapped with <PerformanceProfiler /> content layer.

import React, {useState} from 'react';
import {
  SafeAreaView,
  StyleSheet,
  Text,
  TouchableOpacity,
  View,
  useColorScheme,
} from 'react-native';

import {Colors} from 'react-native/Libraries/NewAppScreen';

import {
  useResetFlow,
  PerformanceMeasureView,
} from '@shopify/react-native-performance';

function ScreenA(): JSX.Element {
  const {resetFlow, componentInstanceId} = useResetFlow();
  const [resetId, setResetId] = useState(0);

  const reRenderScreen = () => {
    resetFlow({
      destination: 'ScreenA',
    });

    console.log('Re-rendering screen');

    setResetId(resetId + 1);
  };

  return (
    <PerformanceMeasureView
      componentInstanceId={componentInstanceId}
      screenName="ScreenA"
      interactive={true}>
      <SafeAreaView>
        <View style={styles.contentsContainer}>
          <TouchableOpacity style={styles.button} onPress={reRenderScreen}>
            <Text style={styles.rerenderButton}>Rerender</Text>
          </TouchableOpacity>

          <View style={styles.resetCounterContainer}>
            <Text style={styles.resetId}>{resetId}</Text>
          </View>
        </View>
      </SafeAreaView>
    </PerformanceMeasureView>
  );
}

const styles = StyleSheet.create({
  ...
});

export default ScreenA;

When I press the Rerender button I get the following error

 ERROR  RenderTimeoutError: Screen 'ScreenA' failed to render in 5000 milliseconds. One of the following could happen:
1. You notified the profiler of the navigation-start event via the useStartProfiler hook, but forgot to notify of the render-completion event via <PerformanceMeasureView/>
Read the usage here: https://shopify.github.io/react-native-performance/fundamentals/measuring-render-times.
2. You use useStartProfiler hook instead of useResetFlow hook when re-render is occurring because the flow is essentially being restarted.
Read the usage here: https://shopify.github.io/react-native-performance/fundamentals/measuring-render-times#3-measuring-screen-re-render-times.
 The state at timeout was: {
  "name": "Started",
  "destinationScreen": "ScreenA",
  "componentInstanceId": "0",
  "previousState": "Rendered",
  "timestamp": {
    "jsTimestamp": 1693757078630
  },
  "operationsSnapshot": {
    "operationTimestamps": {}
  },
  "ongoingOperations": {
    "operationTimestamps": {}
  },
  "sourceScreen": "ScreenA",
  "type": "flow_reset"
}.

Not sure what is wrong with the code, any help would be much appreciated.

agatharejina commented 11 months ago

hi, do you have any solution for this?