๐ react-native-performance๋ก ์ฑ ์์ ์๊ฐ ์ธก์ ํ๊ธฐ
์ด๋ฒ์ ํ์ฌ์์ ์ฑ ์ฑ๋ฅ ๊ฐ์ ์ ๋ฌด๋ฅผ ๋งก์ ์ ๋ง ์ด์ฌํ ํ์ต๋๋ค.
๊ทธ ๊ณผ์ ์์ ์ฑ ์์ ์๋๋ ์ ๋ง ํฌ๊ฒ ๊ฐ์ ๋์๋๋ฐ, ์์น๋ก ๋ณด์ฌ์ฃผ์ง ์์ผ๋ฉด ๊ทธ์ ๊ฐ์ผ๋ฟ์ด๊ฒ ์ฃ ?
์์นํ๋ฅผ ํ๋ ค๊ณ ํ๋กํ์ผ๋ง ๋๊ตฌ๋ค์ ๋ง์ด ์ฐพ์๋ณด๋ค react-native-performance
๋ผ๋ ํจํค์ง๋ฅผ ์ ํํ๊ฒ ๋์์ต๋๋ค.
๊ฐ์ฅ ์ฃผ์ํ ์ด์ ๋ Cold Start ์ ์ฑ ๋ฒ๋ค ๋ก๋ ์๊ฐ์ ์ธก์ ํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
๊ทธ๋ผ ์ธํ ๋ถํฐ ์ด๊ธฐ ๋ฒ๋ค ๋ก๋ ์๊ฐ + ์ด๊ธฐ ํ๋ฉด ๋ ๋๋ง ์๊ฐ ํ๋กํ์ผ๋ง๊น์ง ์๊ฐ๋๋ฆฝ๋๋ค.
๐ ์ค์น
https://shopify.github.io/react-native-performance/
$ yarn add @shopify/react-native-performance
$ cd ios && pod install
ํจํค์ง ์ค์น ํ pod install๊น์ง ์งํํฉ๋๋ค.
๐ Native ์ธํ
๋ค์ดํฐ๋ธ ์ฝ๋์ ์ฑ ์์ ์ ์ธก์ ์ฝ๋๋ฅผ ์ถ๊ฐํด ์ด๊ธฐ ๋ฒ๋ค ๋ก๋ ์๊ฐ์ ์ธก์ ํ ์ ์์ต๋๋ค.
๐ Android
// MainApplication.java
import com.shopify.reactnativeperformance.ReactNativePerformance; // ์ถ๊ฐ
// ...
@Override
public void onCreate() {
ReactNativePerformance.onAppStarted(); // ์ถ๊ฐ
super.onCreate();
// ...
}
// MainApplication.kt
import com.shopify.reactnativeperformance.ReactNativePerformance; // ์ถ๊ฐ
// ...
public void onCreate() {
ReactNativePerformance.onAppStarted(); // ์ถ๊ฐ
super.onCreate();
// ...
}
์๋๋ก์ด๋๋ Java or Kotlin์ ๋ฐ๋ผ MainApplication
์ ์ฝ๋๋ฅผ ์ถ๊ฐํด ์ค๋๋ค.
์ฌ๊ธฐ์ ํต์ฌ์ onCreate() ์ ์ onAppStarted() ๋ฉ์๋๋ฅผ ์คํํด ๋ฒ๋ค ๋ก๋ ์๊ฐ ์ธก์ ์ ์์ํ๋ ๊ฒ๋๋ค.
๐ IOS
// AppDelegate.m
#import <ReactNativePerformance/ReactNativePerformance.h> // ์ถ๊ฐ
// ...
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[ReactNativePerformance onAppStarted]; // ์ถ๊ฐ
// ...
}
// AppDelegate.swift
import ReactNativePerformance // ์ถ๊ฐ
//...
@main
class AppDelegate: RCTAppDelegate {
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
ReactNativePerformance.onAppStarted() // ์ถ๊ฐ
// ...
}
IOS๋ Objective-C or Swift์ ๋ฐ๋ผ AppDelegate
์ ์ฑ ์์ ์ธก์ ์ฝ๋๋ฅผ ์ถ๊ฐํด ์ฃผ๋๋ก ํฉ๋๋ค.
๐ ์ฑ ์์ ์๋ ์ธก์
// App.tsx
import React, { useCallback } from 'react';
import { RenderPassReport, PerformanceProfiler, PerformanceMeasureView } from '@shopify/react-native-performance';
import { createStackNavigator } from '@react-navigation/stack';
import { NavigationContainer } from '@react-navigation/native';
import Home from './src/pages/Home';
const RootStack = createStackNavigator();
const PerformanceHomeScreen = () => {
return (
<PerformanceMeasureView screenName="Home" interactive={true}>
<Home />
</PerformanceMeasureView>
);
};
function App() {
const onReportPrepared = useCallback((report: RenderPassReport) => {
console.log({ report });
}, []);
return (
<PerformanceProfiler onReportPrepared={onReportPrepared}>
<NavigationContainer>
<RootStack.Navigator initialRouteName="Home">
<RootStack.Screen name="Home" component={PerformanceHomeScreen} />
</RootStack.Navigator>
</NavigationContainer>
</PerformanceProfiler>
);
}
export default App;
- App.tsx์์
<PerformanceProfiler />
๋ฅผ ์ ์ธํจ์ผ๋ก์จ ํ๋กํ์ผ๋ง์ ์ด๊ธฐํํด ์ฃผ๊ณ , ์ธก์ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค. <PerformanceMeasureView />
๋ฅผ ์ต์ด ๋ ๋ ํ์ด์ง Navigator Screen์ ์ ์ฉํ๋ฉฐ ํ๋ฉด์ด ๋ ๋ ๋ ๋ ์ธก์ ์ ์ข ๋ฃํฉ๋๋ค.
๐ ๋ฐ์ดํฐ ํ์ธ
{
"reportId": "22B199F0-637F-4122-9FE1-F95A13170950",
"resourceAcquisitionStatus": {
"totalTimeMillis": 0,
"components": {}
},
"flowInstanceId": "B02EB9F0-37F2-4EBC-94E6-5B97269E1A5E",
"destinationScreen": "Home",
"flowStartTimeSinceEpochMillis": 1747417857111,
"timeToBootJsMillis": 1625.4560546875,
"renderPassName": "interactive",
"timeToRenderMillis": 210.14794921875,
"interactive": true
}
PerformanceProfiler์ onReportPrepared์ ํตํด ๋ฐ์ ๋ฐ์ดํฐ์ ๋๋ค.
๊ฐ ๋ฐ์ดํฐ์ ์๋ฏธ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- destinationScreen
- ํ๋กํ์ผ๋ง ๋ ๋์ฐฉ ์คํฌ๋ฆฐ์ ๋๋ค.
- flowInstanceId
- ํ๋์ flow ์คํ์์ ๋ฐ์ํ ๋ชจ๋ ๋ ๋๋ง ๋ฆฌํฌํธ๊ฐ ๊ณต์ ํ๋ ๊ณ ์ ํ UUID์ ๋๋ค.
- flowStartTimeSinceEpochMillis
- flow๊ฐ ์์๋ ์์ ์ ํ์์คํฌํ์ ๋๋ค.
- interactive
- ํด๋น ๋ ๋ ํจ์ค๊ฐ ํ๋ฉด์ ์ธํฐ๋ํฐ๋ธ ์ํ๋ก ๋ง๋ค์๋์ง๋ฅผ ๋ํ๋
๋๋ค.
PerformanceMeasureView์ interactive prop์ ์ํด ์ ์ด๋ฉ๋๋ค.
- ํด๋น ๋ ๋ ํจ์ค๊ฐ ํ๋ฉด์ ์ธํฐ๋ํฐ๋ธ ์ํ๋ก ๋ง๋ค์๋์ง๋ฅผ ๋ํ๋
๋๋ค.
- renderPassName
- ์๋ฃ๋ ๋ ๋ ํจ์ค์ ์ด๋ฆ์ ๋๋ค. ์ค๋จ๋ ๋ ๋ ํจ์ค์ ๊ฒฝ์ฐ์๋ ์ ๊ณต๋์ง ์์ต๋๋ค.
- reportId
- ๊ฐ ๋ ๋๋ง์ ๋ํด ๊ณ ์ ํ๊ฒ ์๋ณ๋๋ UUID์ ๋๋ค.
- sourceScreen
- ํ๋กํ์ผ๋ง๋ flow์ ์์ ์คํฌ๋ฆฐ์ ๋๋ค.
- timeToBootJsMillis
- JS ์ฝ๋๊ฐ ๋ถํ ๋๊ธฐ๊น์ง ๊ฑธ๋ฆฐ ์๊ฐ์ ๋๋ค. ์ฑ ์์ ๋ ๋๋ง ์๊ฐ์ ์ธก์ ํ ๋๋ง ์ฌ์ฉ ๊ฐ๋ฅํฉ๋๋ค.
- timeToRenderMillis
- ๋ ๋ ํจ์ค๊ฐ ์๋ฃ๋๊ธฐ๊น์ง ๊ฑธ๋ฆฐ ์๊ฐ์ ๋๋ค. ์ค๋จ๋ ๋ ๋ ํจ์ค์ ๊ฒฝ์ฐ์๋ ์ ๊ณต๋์ง ์์ต๋๋ค.
- timeToAbortMillis
- ๋ ๋ ํจ์ค๊ฐ ์ค๋จ๋๊ธฐ๊น์ง ๊ฑธ๋ฆฐ ์๊ฐ์ ๋๋ค. ์ค๋จ๋ ๋ ๋ ํจ์ค์ ๊ฒฝ์ฐ์๋ง ์ฌ์ฉ ๊ฐ๋ฅํฉ๋๋ค.
์ฌ๊ธฐ์ ์ค์ํ ๊ฑด timeToBootJsMillis
์ timeToRenderMillis
์
๋๋ค.
์ด ๋์ ์ด์ฉํ๋ค๋ฉด "์ฑ ์์ ํ ์ฒซ ์ฝํ ์ธ ๋ ๋๋ง ์์ ์๊ฐ"์ธ "First Contentful Paint(FCP)"๋ฅผ ์ธก์ ํ ์ ์์ต๋๋ค.
FCP = ๋ฒ๋ค ๋ก๋ ์๊ฐ(timeToBootJsMillis) + ์ปจํ ์ธ ๋ ๋ ์๊ฐ(timeToRenderMillis)
๊ทธ๋ผ ์ ๋ฐ์ดํฐ๋ฅผ ๋ดค์ ๋ timeToBootJsMillis๊ฐ 1625ms, timeToRenderMillis๊ฐ 210ms์ด๋๊น ์ฑ ์์ ์๋๋ 1.8์ด ์ ๋ ๋๊ฒ ์ฃ ?
์ ๋ Navigator ๋จ์ PerformanceMeasureView๋ฅผ ์ ์ฉํ์์ง๋ง, ์ปดํฌ๋ํธ ๋ด๋ถ์ ์ง์ ์ ์ฉํ ๋ค interactive props์ ์ด์ฉํ๋ค๋ฉด ์ฒซ ์ํธ์์ฉ ์๊ฐ ์งํ์ธ Time To Interactive(TTI)๋ฅผ ์ธก์ ํ ์ ์์ต๋๋ค.
๐ ๋ง๋ฌด๋ฆฌํ๋ฉฐ
react-native-performance ํจํค์ง๊ฐ ์ปค๋ฎค๋ํฐ๋ ํ์ฑ๋์ด ์์ง ์์ ํ์ฉํ๊ธฐ์ ๊น๊ฒ ์ฌ์ฉํ๊ธฐ์ ์ด๋ ต์ง๋ง ์ฑ ์์ ์๋๋ฅผ ์ธก์ ํ๊ธฐ์ ๊ฐ๋จํ๊ณ ์ฌ์ด ๊ฒ ๊ฐ์ ๋ง์กฑํฉ๋๋ค.
์ฌ์ฉ ๋ฐฉ๋ฒ์ ๋ด์ ์์ ๋ ๋ค์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํด์ฃผ์ธ์.
GitHub - devlasbe/rn-lazy-loading: React Native์์ Lazy Loading์ ํตํด ์ฑ ์์ ์๋๋ฅผ ์ธก์
React Native์์ Lazy Loading์ ํตํด ์ฑ ์์ ์๋๋ฅผ ์ธก์ . Contribute to devlasbe/rn-lazy-loading development by creating an account on GitHub.
github.com
'React-Native' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
React Native Lazy Loading์ผ๋ก ์ฑ ์์ ์๋ ๊ฐ์ ํ๊ธฐ (0) | 2025.05.19 |
---|---|
react-native ๋ฒ์ ์ ๊ทธ๋ ์ด๋ ๊ฐ์ด๋, v0.69 to v0.78 (0) | 2025.04.19 |
2025๋ React Native ํํฉ๊ณผ CLI vs Expo ๋น๊ต๋ถ์ (2) | 2025.01.15 |
[React Native] Android Native-Module Event Listener ๋ง๋ค๊ธฐ (0) | 2025.01.10 |
[React-Native] ScrollView ์คํฌ๋กค ๋ฒ๋ฒ ์ ์ต์ ํํ๊ธฐ (2) | 2023.10.14 |
๋๊ธ