React Native — Ultimate Guide on Debugging , Profiling & Advanced Optimization (iOS + Android)
Accessing the Dev Menu
React Native provides an in-app developer menu which offers several debugging options. You can access the Dev Menu by shaking your device or via keyboard shortcuts.
Alternatively for Android devices and emulators, you can run adb shell input keyevent 82 in your terminal.
Also you can use VSCode extension React Native Tools to open dev menu (bridge). Install the extension & then press Cmd ? + Shift + P and type React Native: Show Dev Menu & hit enter.
The Dev Menu is disabled in release (production) builds.
Dev menu is looking like below (IOS & Android)
Let’s Understand options of Dev Menu (Bridge) ??
Fast Refresh
Fast Refresh is a React Native feature that allows you to get near-instant feedback for changes in your React components. Fast Refresh is enabled by default, and you can toggle “Enable Fast Refresh” in the React Native Dev Menu. With Fast Refresh enabled, most edits should be visible within a second or two.
How Fast Refresh works?
Error Resilience of Fast Refresh
If you make a syntax error during a Fast Refresh session, you can fix it and save the file again. The redbox will disappear. Modules with syntax errors are prevented from running, so you won’t need to reload the app.
If you make a runtime error during the module initialization (for example, typing Style.create instead of StyleSheet.create), the Fast Refresh session will continue once you fix the error. The redbox will disappear, and the module will be updated.
If you make a mistake that leads to a runtime error inside your component, the Fast Refresh session will also continue after you fix the error. In that case, React will remount your application using the updated code.
Limitations of Fast Refresh
Fast Refresh tries to preserve local React state in the component you’re editing, but only if it’s safe to do so. Here’s a few reasons why you might see local state being reset on every edit to a file:
Pro Tips about Fast Refresh
Sometimes you might want to force the state to be reset, and a component to be remounted. For example, this can be handy if you’re tweaking an animation that only happens on mount. To do this, you can add // @refresh reset anywhere in the file you're editing. This directive is local to the file, and instructs Fast Refresh to remount components defined in that file on every edit.
Fast Refresh and Hooks
When possible, Fast Refresh attempts to preserve the state of your component between edits. In particular, useState and useRef preserve their previous values as long as you don't change their arguments or the order of the Hook calls.
Hooks with dependencies — such as useEffect, useMemo, and useCallback—will always update during Fast Refresh. Their list of dependencies will be ignored while Fast Refresh is happening.
LogBox
Errors and warnings in development builds are displayed in LogBox inside your app.
LogBox is disabled in release (production) builds.
This is how LogBox look like
Console Errors and Warnings
Console errors and warnings are displayed as on-screen notifications with a red or yellow badge, and the number of errors or warning in the console respectively. To view a console error or warnings, tap the notification to view the full screen information about the log and to paginate through all of the logs in the console.
These notifications can be hidden using LogBox.ignoreAllLogs(). This is useful when giving product demos, for example. Additionally, notifications can be hidden on a per-log basis via LogBox.ignoreLogs(). This is useful when there's a noisy warning that cannot be fixed, like those in a third-party dependency.
Unhandled JavaScript errors such as undefined is not a function will automatically open a full screen LogBox error with the source of the error.
When syntax error occurs the full screen LogBox error will automatically open with the stack trace and location of the syntax error. This error is not dismissible because it represents invalid JavaScript execution that must be fixed before continuing with your app.
Chrome Developer Tools
Follow this only 6 steps to activate “Chrome Developer Tool” for React Native App
Useful Commands to copy & run
These are the commands I used to activate my chrome debug tools for React Native.
领英推荐
Tips & links
Output of Chrome Developer tools (Android)
Output of Chrome Developer tools (IOS)
Debugging on a physical device (Android)
On Android 5.0+ devices connected via USB, you can use the adb command line tool to set up port forwarding from the device to your computer.
Command: adb reverse tcp:8081 tcp:8081
Alternatively, select “Settings” from the Dev Menu, then update the “Debug server host for device” setting to match the IP address of your computer.
Debugging on a physical device (IOS)
On iOS devices, open the file RCTWebSocketExecutor.mm and change "localhost" to the IP address of your computer, then select "Debug JS Remotely" from the Dev Menu.
Pro Tip (Issue on Dev Menu/ Debug tool)
If you run into any issues, it may be possible that one of your Chrome extensions is interacting in unexpected ways with the debugger. Just Restart your laptop/ pc as it solved mine after an exhaustive findings of in where actually still it connecting to an old debug tool.
Performance Monitor
You can enable a performance overlay to help you debug performance problems by selecting “Show Perf Monitor” from the Dev Menu like below.
So, now below is the image from my React Native app (IOS + Android) after opening Performance Monitor
The performance monitor in React Native app shows you some metrics that can help you to optimize your app’s performance and user experience. Here’s what each of the numbers means.
Details about FPS (Frame Per Second)
A compelling reason for using React Native instead of WebView-based tools is to achieve 60 frames per second and a native look and feel to your apps.
Your grandparents’ generation called movies “moving pictures” for a reason: realistic motion in video is an illusion created by quickly changing static images at a consistent speed. React Native team refers to each of these images as frames. The number of frames that is displayed each second has a direct impact on how smooth and ultimately life-like a video (or user interface) seems to be. iOS devices display 60 frames per second, which gives you and the UI system about 16.67ms to do all of the work needed to generate the static image (frame) that the user will see on the screen for that interval. If you are unable to do the work necessary to generate that frame within the allotted 16.67ms, then you will “drop a frame” and the UI will appear unresponsive.
Now to confuse the matter a little bit, open up the Dev Menu in your app and toggle Show Perf Monitor. You will notice that there are two different frame rates.
There are two types of Frame rate
JS frame rate (JavaScript thread)
For most React Native applications, your business logic will run on the JavaScript thread. This is where your React application lives, API calls are made, touch events are processed, etc… Updates to native-backed views are batched and sent over to the native side at the end of each iteration of the event loop, before the frame deadline (if all goes well).
If the JavaScript thread is unresponsive for a frame, it will be considered a dropped frame. For example, if you were to call this.setState on the root component of a complex application and it resulted in re-rendering computationally expensive component subtrees, it's conceivable that this might take 200ms and result in 12 frames being dropped. Any animations controlled by JavaScript would appear to freeze during that time. If anything takes longer than 100ms, the user will feel it.
?? JS thread LOW FPS happens during Navigator transitions.
When you push a new route, the JavaScript thread needs to render all of the components necessary for the scene in order to send over the proper commands to the native side to create the backing views. It’s common for the work being done here to take a few frames and cause jank because the transition is controlled by the JavaScript thread. Sometimes components will do additional work on componentDidMount, which might result in a second stutter in the transition.
?? Another example is View not responding to touches due to low JS FPS.
If you are doing work across multiple frames on the JavaScript thread, you might notice a delay in responding to TouchableOpacity, for example. This is because the JavaScript thread is busy and cannot process the raw touch events sent over from the main thread. As a result, TouchableOpacity cannot react to the touch events and command the native view to adjust its opacity.
UI frame rate (main thread)
Many people have noticed that performance of NavigatorIOS is better out of the box than Navigator. The reason for this is that the animations for the transitions are done entirely on the main thread, and so they are not interrupted by frame drops on the JavaScript thread.
Similarly, you can happily scroll up and down through a ScrollView when the JavaScript thread is locked up because the ScrollViewlives on the main thread. The scroll events are dispatched to the JS thread, but their receipt is not necessary for the scroll to occur.
Common reasons of performance problems (Getting low FPS)
function handleOnPress() {
requestAnimationFrame(() => {
this.doExpensiveAction();
});
}
a Comprehensive Solution for Sales & Distribution Management
8 个月Oh Great!
?Software Engineer | .NET Developer | Database
8 个月c?m ?n anh!