React Native
Մեկ React codebase, երկու իսկապես native հավելված, և ինչպես կառուցել դրանք զրոյից։
30 վայրկյանում
React Native-ը թույլ է տալիս մոբայլ հավելված գրել React-ով և TypeScript-ով, մինչդեռ էկրանները նկարվում են իրական iOS և Android կոմպոնենտներով։ Ձեր JavaScript-ն աշխատում է Hermes շարժիչում և New Architecture-ի միջոցով ուղղակիորեն խոսում native կոդի հետ։ Լավ կառուցվածքով՝ navigation, store-եր, API layer և design token-ներ, մեկ թիմը կարող է release անել և սպասարկել երկու հավելվածն էլ մեկ codebase-ից։
Ինչու եմ օգտագործում
- Ես օգտագործում եմ React Native, որովհետև մեկ TypeScript codebase-ը հաճախորդին տալիս է և՛ iOS, և՛ Android հավելվածներ, որոնք բիզնես տրամաբանությունը կիսում են իրենց React վեբ frontend-ի հետ։
- Հավելվածները կառուցում եմ ընդհանուր ներքին template-ի վրա, այնպես որ auth-ը, API հասանելիությունը, theming-ը, push-ը և force-update-ը լուծված են մեկ անգամ, և յուրաքանչյուր նոր հավելված սկսվում է աշխատող հիմքից։
- New Architecture-ը և Hermes-ը արագագործությունը դարձնում են բավարար, որ commerce, լոյալության և ամրագրման հավելվածներում օգտատերերը տարբերություն չնկատեն։
- Երբ ֆունկցիային պետք է պլատֆորմը՝ վճարային SDK, տեսախցիկով սքանավորում, քարտեզներ, կարող եմ այդ մեկ մոդուլի համար իջնել Kotlin կամ Swift, իսկ մնացածը պահել React-ում։
Ինչպես է աշխատում
01Ինչպես է աշխատում React Native-ը
Ձեր հավելվածն ունի երկու աշխարհ։ JavaScript աշխարհը Hermes-ի ներսում աշխատեցնում է ձեր React կոմպոնենտները, state-ը և բիզնես տրամաբանությունը․ Hermes-ը մոբայլի համար կառուցված JavaScript շարժիչ է, որը build-ի ժամանակ ձեր կոդը compile է անում bytecode-ի, որպեսզի հավելվածներն ավելի արագ մեկնարկեն և ավելի քիչ հիշողություն օգտագործեն։ Native աշխարհին են պատկանում իրական UIView և Android View օբյեկտները, տեսախցիկը, keychain-ը և այլն։ React-ը նկարագրում է, թե ինչպիսին պետք է լինի էկրանը, իսկ React Native-ը այդ նկարագրությունը վերածում է native view-երի։ <View>-ն iOS-ում դառնում է UIView, Android-ում՝ ViewGroup, <Text>-ը դառնում է native տեքստ։ WebView չկա․ scroll-ը, ժեստերը և տեքստի մուտքագրումը native են, ահա թե ինչու RN հավելվածները զգացվում են որպես իրական հավելվածներ։ Layout-ն օգտագործում է Yoga՝ Flexbox իրականացնող շարժիչ, այնպես որ նույն style-ն աշխատում է երկու պլատֆորմներում էլ։
02New Architecture՝ JSI, Fabric, TurboModules
Հին ճարտարապետությունը JavaScript-ի և native-ի միջև յուրաքանչյուր հաղորդագրություն ուղարկում էր serialize արված JSON-ով ասինխրոն «bridge»-ի միջոցով՝ queue, որը խցան էր դառնում անիմացիաների և մեծ ցուցակների համար։ New Architecture-ը, որը default է 0.76-ից և միակ տարբերակը՝ 0.82-ից, փոխարինում է այն։ JSI-ը (JavaScript Interface) թույլ է տալիս JavaScript-ին պահել C++ օբյեկտների ուղղակի հղումներ և կանչել դրանք սինխրոն՝ առանց serialize անելու։ Fabric-ը նոր renderer-ն է․ այն UI ծառը կառուցում է C++-ում, աջակցում է React 18+ concurrent հնարավորություններին և կարող է սինխրոն չափել ու թարմացնել layout-ը։ TurboModules-ը native մոդուլներ են, որոնք lazy կերպով բեռնվում են առաջին օգտագործման ժամանակ և տիպավորվում են Codegen-ի միջոցով, որը ձեր TypeScript spec-ից գեներացնում է C++ glue-ն, այնպես որ սխալները երևում են build-ի ժամանակ։ Գործնական ազդեցություն՝ ավելի հարթ ժեստեր և անիմացիաներ (Reanimated 4-ին դա պետք է), ավելի արագ մեկնարկ, և գրադարանները պետք է համատեղելի լինեն New Architecture-ի հետ, ստուգեք նախքան տեղադրելը։
- JSI՝ ուղղակի, սինխրոն JS ↔ C++ կանչեր, առանց JSON bridge-ի
- Fabric՝ C++ renderer, concurrent React, սինխրոն layout
- TurboModules + Codegen՝ lazy, type-safe native մոդուլներ
- Hermes՝ bytecode-ի compile արվող շարժիչ, default երկու պլատֆորմներում էլ
03Bare React Native, թե՞ Expo
React Native թիմն այժմ խորհուրդ է տալիս սկսել framework-ով, և Expo-ն գլխավորն է։ Expo-ն տալիս է սպասարկվող native մոդուլների մեծ հավաքածու, ֆայլերի վրա հիմնված routing (Expo Router), config plugin-ներ, որոնք ձեր փոխարեն խմբագրում են native նախագծերը, development build-եր և EAS՝ cloud build-երի, submission-ի և OTA թարմացումների համար։ «Bare»-ը նշանակում է, որ ios/ և android/ թղթապանակներն ուղղակիորեն ձերն են (սկսված React Native Community CLI-ով)։ Bare-ը տալիս է լիարժեք վերահսկողություն և հարմար է native փորձ ունեցող կամ ծանր custom native SDK-ներով թիմերի համար։ Սահմանը մշուշոտվել է․ Expo հավելվածները կարող են ներառել ցանկացած native կոդ config plugin-ների կամ prebuild-ի միջոցով, իսկ bare հավելվածները կարող են օգտագործել Expo մոդուլներ։ Իմ կանոնը՝ ստանդարտ կարիքներով նոր պրոդուկտի համար սկսեք Expo-ով․ այն հավելվածի համար, որը պետք է ինտեգրի անսովոր native SDK-ներ կամ հետևում է գոյություն ունեցող native template-ի, bare-ը նորմալ է, պարզապես պարբերաբար upgrade արեք։
# Expo (recommended start)
npx create-expo-app@latest my-app --template default
cd my-app && npx expo start
# Bare React Native (Community CLI)
npx @react-native-community/cli@latest init MyApp
cd MyApp && npx react-native run-ios
04Իրական հավելվածի կառուցում զրոյից՝ կառուցվածք, env, API, state
Կառուցվածքը դասավորեք ըստ feature-ի, ոչ թե ըստ ֆայլի տեսակի, որպեսզի էկրանը, դրա hook-երը և կոմպոնենտներն ապրեն միասին։ Երեք layer պահեք առանձին։ API layer-ը մեկ HTTP client է՝ base URL-ով, auth header-ով, token refresh-ով և timeout-ներով․ adapter-ները backend-ի պատասխանները վերածում են հավելվածի տիպերի, այնպես որ backend-ում վերանվանված դաշտը փոխում է մեկ ֆայլ, ոչ թե քսան էկրան։ Store-երը (Zustand-ը թեթև է և լավ է աշխատում) պահում են հավելվածի state-ը, օրինակ՝ session, զամբյուղ և կարգավորումներ․ էկրանները կարդում են store-երը և կանչում action-ներ, երբեք ուղղակիորեն fetch չեն անում։ Սերվերային տվյալների համար TanStack Query-ն ավելացնում է caching, retry-ներ և refetch՝ focus-ի ժամանակ։ Միջավայր՝ API URL-ը և key-երը պահեք ըստ build-ի (dev, staging, prod)՝ build-time config-ի միջոցով, երբեք hard-code մի արեք և երբեք իրական գաղտնիքներ մի դրեք հավելվածում․ bundle-ում եղած ամեն ինչ կարելի է դուրս հանել։ Ավտոմատ retry արեք միայն idempotent հարցումները (GET, PUT՝ key-երով)․ կրկնված POST-ը կարող է կրկնօրինակ պատվեր ստեղծել։
src/
app/ # navigation, providers, deep links
features/
auth/ # screens, hooks, components for sign-in
cart/
orders/
shared/
api/ # http client, adapters, endpoints
stores/ # zustand stores (session, cart, settings)
ui/ # Button, Text, Card — built on tokens
theme/ # colors, spacing, typography tokens
i18n/ # en / hy / ru dictionaries
native/ # bridges to custom native modules
05Navigation, auth flow և push
React Navigation-ը (stack, tab-եր, drawer-ներ native էկրանների վրա) և Expo Router-ը (ֆայլերի վրա հիմնված, կառուցված React Navigation-ի վրա) ստանդարտ ընտրություններն են։ Auth-ը մոդելավորեք որպես navigation state․ root navigator-ը ցույց է տալիս auth stack-ը կամ հիմնական tab-երը՝ կախված նրանից, թե session կա արդյոք, այնպես որ դուրս եկած օգտատերը չի կարող deep link-ով հասնել private էկրանների։ Token-ները պահեք Keychain/Keystore-ում (react-native-keychain կամ expo-secure-store), երբեք AsyncStorage-ում։ Թույլ տվեք հյուրերին թերթել և սահմանափակեք միայն այն գործողությունները, որոնց հաշիվ է պետք, sign-in-ից հետո վերադարձնելով նրանց նույն տեղը։ Deep link-երը և Universal/App Links-ը կարգավորեք վաղ․ push ծանուցումները, email-ները և QR կոդերը բոլորը կախված են դրանցից։ Push-ի համար սարքի token-ը գրանցեք sign-in-ից հետո և ուղարկեք ձեր backend-ին, թույլտվություն խնդրեք իմաստալից պահին, ոչ թե առաջին գործարկման ժամանակ, և ծանուցումների tap-երը մշակեք՝ navigate անելով նույն deep-link route-երով։
const Stack = createNativeStackNavigator<RootParams>();
export function RootNavigator() {
const session = useSession((s) => s.session);
return (
<Stack.Navigator screenOptions={{ headerShown: false }}>
{session ? (
<Stack.Screen name="Main" component={MainTabs} />
) : (
<Stack.Screen name="Auth" component={AuthStack} />
)}
<Stack.Screen name="ForceUpdate" component={ForceUpdateScreen} />
</Stack.Navigator>
);
}
06Styling, design token-ներ և ցուցակների արագագործություն
CSS cascade չկա․ յուրաքանչյուր կոմպոնենտ ստանում է style օբյեկտ, և StyleSheet.create-ը դրանք ստատիկ է պահում։ Կառուցեք token-ների փոքր theme՝ գույներ (light և dark), spacing սանդղակ, radius-ներ, տիպոգրաֆիա, և մի քանի բազային կոմպոնենտ (Text, Button, Card, Screen), որոնք օգտագործում են միայն token-ներ։ Այդ դեպքում էկրանները երբեք չեն պարունակում raw hex արժեքներ կամ «կախարդական» թվեր, իսկ dark mode-ը կամ rebrand-ը մեկ ֆայլ է։ Հարգեք safe area-ները (react-native-safe-area-context), Dynamic Type/font scaling-ը և Android-ի edge-to-edge layout-ները։ Երկար ցուցակները երբեք մի render արեք map-ով ScrollView-ի ներսում․ օգտագործեք FlatList կամ, ավելի լավ, FlashList, որը վերաօգտագործում է cell-երը։ Տարրերին տվեք կայուն key-եր, memoize արեք row կոմպոնենտները, renderItem-ում խուսափեք inline ծանր աշխատանքից և նկարները ճիշտ չափսավորեք (expo-image կամ cache անող image գրադարան)։ Անիմացիաներն արեք Reanimated-ով, որը անիմացիաներն աշխատեցնում է UI thread-ի վրա, այնպես որ դրանք մնում են հարթ նույնիսկ այն ժամանակ, երբ JavaScript-ը զբաղված է։
export const theme = {
color: { bg: "#FFFFFF", text: "#111111", primary: "#0A6CFF", muted: "#6B7280" },
space: { xs: 4, sm: 8, md: 16, lg: 24, xl: 32 },
radius: { sm: 6, md: 12, pill: 999 },
font: { body: 16, title: 22, caption: 13 },
} as const;
<FlashList
data={products}
keyExtractor={(p) => p.id}
renderItem={({ item }) => <ProductRow product={item} />}
/>
07Native մոդուլներ, պլատֆորմների տարբերություններ և debugging
Երբ գրադարան գոյություն չունի՝ տարածաշրջանային վճարային SDK, տպիչ, custom սկաներ, գրեք TurboModule՝ TypeScript spec, Codegen, ապա Kotlin/Swift իրականացումներ (Expo Modules API-ն ավելի բարեհամբույր այլընտրանք է)։ Մակերեսը պահեք փոքր և promise-ի վրա հիմնված։ Սպասեք պլատֆորմների տարբերությունների՝ թույլտվությունների flow-եր, back կոճակ Android-ում, ստեղնաշարի վարքագիծ, ստվերներ (iOS-ի shadow props ընդդեմ Android-ի elevation-ի), ամսաթվի picker-ներ, տառատեսակներ և iOS-ում ավելի խիստ background սահմանափակումներ։ Platform.select կամ ֆայլերի suffix-ներ (Button.ios.tsx) օգտագործեք միայն այնտեղ, որտեղ վարքագիծն իսկապես տարբերվում է։ Debugging՝ React Native DevTools-ը (Metro-ում սեղմեք j) տալիս է Chrome-ի ոճի debugger, console, React կոմպոնենտներ և profiler Hermes-ի համար։ Native crash-երի համար օգտագործեք Xcode-ի և Android Studio-ի log-երը (Logcat), production-ի համար՝ Crashlytics կամ Sentry, իսկ performance monitor-ը՝ JS-ի և UI-ի frame rate-ին հետևելու համար։ Թեստավորեք իրական թույլ Android հեռախոսի վրա․ simulator-ը ստում է արագագործության մասին։
Օգտագործեք, երբ
- Ձեզ պետք են iOS և Android հավելվածներ՝ հիմնականում ընդհանուր UI-ով և բիզնես տրամաբանությամբ, և սահմանափակ բյուջե։
- Ձեր թիմն արդեն գիտի React և TypeScript, կամ կոդ ու տիպեր է կիսում React վեբ հավելվածի հետ։
- Commerce, ամրագրման, լոյալության, CRM և կոնտենտի հավելվածներ, որտեղ native տեսքն ու զգացողությունը կարևոր են, բայց UI-ը ստանդարտ է։
- Ուզում եք OTA թարմացումներ JavaScript ուղղումների համար և արագ իտերացիա՝ մեկ release process-ով։
Մի՛ օգտագործեք, երբ
- Գրաֆիկայով ծանր խաղեր կամ AR՝ օգտագործեք խաղային շարժիչ (Unity, Godot) կամ native։
- Հավելվածներ, որոնք հիմնականում պլատֆորմի խորը հնարավորություններ են (watch face-եր, բարդ widget-ներ, background աուդիոյի մշակում)՝ քիչ ընդհանուր UI-ով։
- Թիմ՝ ուժեղ native iOS և Android ինժեներներով և առանց React փորձի։
Այլընտրանքներ
- Flutter
Իր UI-ը նկարում է սեփական շարժիչով և Dart-ով․ շատ հետևողական պիքսելներ, ավելի քիչ native զգացողություն, առանձին լեզու։
- Native (Swift / Kotlin)
Պլատֆորմի հետ լավագույն ինտեգրացիա և արագագործություն, բայց երկու codebase և երկու թիմ։
- Kotlin Multiplatform
Բիզնես տրամաբանությունը կիսեք Kotlin-ով՝ պահելով native UI (կամ Compose Multiplatform)։
- PWA / Capacitor
Վեբ հավելված shell-ի մեջ․ ամենաէժանն է կոնտենտի հավելվածների համար, ամենաթույլը՝ native զգացողությամբ և store-ում ներկայությամբ։
Լավագույն պրակտիկաներ
- Սկսեք template-ից, որտեղ auth-ը, API client-ը, theme-ը, i18n-ը, push-ը և force-update-ը արդեն միացված են։
- Էկրանները պահեք «բարակ»՝ տվյալները API layer-ի միջոցով adapter-ներով, state-ը store-երում, UI-ը token-ներից։
- Token-ները պահեք Keychain/Keystore-ում․ երբեք գաղտնիքներ մի դրեք bundle-ի ներսում։
- Ավելացնելուց առաջ ստուգեք յուրաքանչյուր գրադարանի New Architecture աջակցությունն ու սպասարկումը։
- Ցուցակների համար օգտագործեք FlashList/FlatList, անիմացիաների համար՝ Reanimated․ profile արեք թույլ Android սարքի վրա։
- React Native-ը upgrade արեք պարբերաբար (Upgrade Helper)՝ միանգամից շատ տարբերակներ ցատկելու փոխարեն։
- Մինչև առաջին release-ը կարգավորեք Crashlytics կամ Sentry, deep link-եր և force-update անջատիչ։
Տարածված սխալներ
- Fetch անել էկրանների ներսում և backend-ի դաշտերի անունները տարածել ամբողջ UI-ով, այնպես որ API-ի յուրաքանչյուր փոփոխություն կոտրում է շատ ֆայլեր։
- Երկար ցուցակները render անել ScrollView + map-ով՝ առաջացնելով հիշողության թռիչքներ և բաց թողնված frame-եր։
- Token-ները պահել AsyncStorage-ում կամ private API key-երը դնել env ֆայլերում, որոնք bundle են արվում հավելվածի մեջ։
- Առաջին գործարկման ժամանակ խնդրել բոլոր թույլտվությունները, այնպես որ օգտատերերը push-ը և location-ը մերժում են ընդմիշտ։
- Թեստավորել միայն iOS simulator-ում և release-ից հետո հայտնաբերել Android-ի ստեղնաշարի, back կոճակի և արագագործության խնդիրներ։
Խորը վերլուծություն
08Thread-երը և render pipeline-ը
React Native հավելվածն աշխատում է մի քանի thread-ի վրա։ JavaScript thread-ը Hermes-ում աշխատեցնում է React-ը, ձեր state-ի թարմացումները և բիզնես տրամաբանությունը։ Main (UI) thread-ին են պատկանում native view-երը, հպումները և պլատֆորմի frame loop-ը։ Fabric-ը render է անում երեք փուլով։ Render․ React-ը ստեղծում է element-ներ, իսկ Fabric-ը կառուցում է C++ node-երից բաղկացած shadow tree։ Commit․ Yoga-ն հաշվարկում է այդ tree-ի layout-ը, հաճախ՝ background thread-ում, և նոր tree-ն առաջ է քաշվում որպես հաջորդը ցուցադրվելու համար։ Mount․ տարբերությունները կիրառվում են իրական native view-երի վրա UI thread-ում։ 60 Hz-ի դեպքում յուրաքանչյուր frame ունի մոտ 16.7 ms, 120 Hz-ի դեպքում՝ մոտ 8 ms։ Եթե JavaScript thread-ը զբաղված է մեծ JSON response parse անելով կամ մեծ tree վերա-render անելով, հպումները դեռ հասնում են, բայց React-ը չի կարող արձագանքել, և հավելվածը թվում է սառած։ Դրա համար են Reanimated-ի worklet-ները անիմացիաները աշխատեցնում UI thread-ում, և դրա համար startTransition-ը կարող է ոչ հրատապ թարմացումները նշել որպես ընդհատելի։
09TurboModule-ի գրում Codegen-ով
TurboModule-ը սկսվում է որպես տիպավորված JavaScript spec։ Ֆայլի անունը պետք է սկսվի Native-ով, իսկ package.json-ը հայտարարում է codegenConfig, որը Codegen-ին ասում է, թե որտեղ են spec-երը։ Build-ի ժամանակ Codegen-ը կարդում է spec-ը և գեներացնում C++ և պլատֆորմային interface-ներ․ ձեր Kotlin և Objective-C++ կամ Swift class-երը իրականացնում են դրանք, և compiler-ը բողոքում է, եթե method-ի signature-ը չի համընկնում։ Մակերեսը պահեք փոքր՝ պարզ տվյալների տիպեր, promise-ներ ամեն դանդաղ բանի համար և event-ներ թարմացումների հոսքերի համար, օրինակ՝ վճարման կարգավիճակը։ Երբեք մի արգելափակեք JavaScript thread-ը սինխրոն native կանչերով, որոնք դիպչում են network-ին կամ disk-ին․ սինխրոն method-ները միայն էժան ընթերցումների համար են։ Եթե թիմը native-ով ուժեղ չէ, Expo Modules API-ն առաջարկում է ավելի պարզ Swift և Kotlin DSL, որն աշխատում է նաև bare հավելվածներում։
// specs/NativePayments.ts
import type { TurboModule } from "react-native";
import { TurboModuleRegistry } from "react-native";
export interface Spec extends TurboModule {
isAvailable(): boolean; // cheap, synchronous
startPayment(amountMinor: number, currency: string): Promise<string>;
}
export default TurboModuleRegistry.getEnforcing<Spec>("NativePayments");
// package.json
// "codegenConfig": { "name": "PaymentsSpec", "type": "modules",
// "jsSrcsDir": "specs", "android": { "javaPackageName": "com.example.payments" } }
10Startup time և bundle-ի չափ
Cold start-ը առաջին տպավորությունն է, և դրա մեծ մասը ձեր վերահսկողության տակ է։ Hermes-ն արդեն մատուցում է նախապես compile արված bytecode, ուստի մնացած ծախսը հիմնականում այն է, ինչ անում է ձեր կոդը module load-ի ժամանակ՝ բոլոր էկրանների և ծանր գրադարանների import-ը սկզբից, storage-ից մեծ տվյալների սինխրոն ընթերցումը կամ շատ SDK-ների initialization-ը մինչև առաջին frame-ը։ Էկրանները բեռնեք lazy, analytics-ը և ոչ կրիտիկական SDK-ները հետաձգեք առաջին render-ից հետո, իսկ splash screen-ը պահեք միայն մինչև առաջին իմաստալից տվյալների պատրաստ լինելը։ Չափեք release build-ով միջին կարգի Android սարքի վրա, երբեք development mode-ում, որը շատ անգամ ավելի դանդաղ է։ Android-ում release-ի համար միացրեք R8 minification-ը և պահեք նրա mapping ֆայլերը Crashlytics-ի համար։ Հետևեք JavaScript bundle-ի չափին ժամանակի ընթացքում․ մեկ ամսաթվի կամ chart-ի գրադարանը կարող է ավելացնել հարյուրավոր կիլոբայթներ, որոնք յուրաքանչյուր օգտատեր ներբեռնում և parse է անում։
11Անվտանգություն և offline կայունություն
Ենթադրեք, որ bundle-ը կկարդացվի․ ցանկացած մեկը կարող է բացել APK կամ IPA և ուսումնասիրել Hermes bytecode-ը և asset-ները։ Secret-ները մնում են սերվերում․ հավելվածը պահում է միայն օգտատիրոջ token-ները Keychain-ում կամ Keystore-ում։ API-ի չարաշահումը դժվարացնելու համար ավելացրեք device attestation (Play Integrity Android-ում, App Attest iOS-ում) և ստուգեք այն սերվերում։ Certificate pinning-ը արգելափակում է որոշ interception հարձակումներ, բայց կարող է բոլոր օգտատերերին դուրս թողնել, եթե certificate-ը անսպասելի rotate լինի, ուստի pin արեք public key-երին՝ backup key-ով և հեռավար kill-switch-ով։ Offline վարքագիծը պահանջում է բացահայտ դիզայն․ հայտնաբերեք կապը, ցույց տվեք cache-ված տվյալները հստակ offline banner-ով, օգտատիրոջ գործողությունները լոկալ դրեք հերթի մեջ և replay արեք idempotency key-երով, որպեսզի կրկնված պատվերը երբեք չկրկնապատկվի։ Sign-out-ի ժամանակ մաքրեք անձնական տվյալներ պարունակող cache-երը, իսկ զգայուն էկրանները բացառեք screenshot-ներից և app switcher-ից, եթե ոլորտը դա պահանջում է։
Իրական իրավիճակներ
Upgrade-ը կոտրվում է, քանի որ գրադարանը պատրաստ չէ New Architecture-ի համար
Խնդիր
React Native-ի հին version-ից 0.82 կամ ավելի նորին անցնելիս build-ը ձախողվում է, կամ էկրանը crash է լինում third-party module-ում, որը գրված է հին bridge-ի համար և մեկ տարի չի թարմացվել։
Ինչպես լուծել
0.82-ից սկսած հին architecture-ը հնարավոր չէ նորից միացնել, ուստի module-ը պետք է աշխատի New Architecture-ի հետ։ Ստուգեք React Native Directory-ն և գրադարանի issue-ները՝ համատեղելի release-ի կամ fork-ի համար։ Շատ legacy module-ներ դեռ աշխատում են interop layer-ի միջոցով, ուստի նախ թեստավորեք դրանք իրական սարքի վրա։ Եթե գրադարանը լքված է, ընտրեք սպասարկվող այլընտրանքի, patch-package-ով ժամանակավոր patch-ի կամ ձեր օգտագործած փոքր մասը որպես TurboModule կամ Expo module վերագրելու միջև։ Upgrade-ն արեք առանձին branch-ում՝ Upgrade Helper-ի diff-ով, մեկ version քայլ միաժամանակ, և merge-ից առաջ անցեք ամբողջ release checklist-ով։
Ապրանքների ցուցակը կմկմում է էժան Android հեռախոսներում
Խնդիր
Flagship iPhone-ի վրա կատալոգը սահուն scroll է լինում, բայց բյուջետային Android սարքի վրա frame-եր է կորցնում, scroll-ի ժամանակ ցույց է տալիս դատարկ cell-եր և երբեմն սպառում է հիշողությունը։
Ինչպես լուծել
Profile արեք release build-ը այդ սարքի վրա React Native DevTools-ով և performance monitor-ով՝ պարզելու համար, թե JavaScript-ի, թե UI thread-ն է bottleneck-ը։ Ցուցակը տեղափոխեք FlashList, memoize արեք row-ը, պահեք կայուն key-եր և փոխանցեք միայն primitive prop-եր, որպեսզի զամբյուղի թարմացումը չվերա-render անի ամեն row։ Սերվերից պահանջեք cell-ի չափի thumbnail-ներ ամբողջական նկարների փոխարեն և օգտագործեք caching-ով image component։ Գնի ֆորմատավորումը և դասավորումը renderItem-ից տեղափոխեք selector։ Pagination արեք API-ը, որպեսզի հավելվածը երբեք չպահի հազարավոր ապրանքներ։ Նորից չափեք և արդյունքը գրանցեք որպես budget ապագա փոփոխությունների համար։
Հավելվածը crash է լինում միայն Android-ի release build-ում
Խնդիր
Debug-ում ամեն ինչ աշխատում է, բայց ստորագրված release build-ը tester-ների մոտ crash է լինում գործարկման ժամանակ։ Կարմիր սխալի էկրան չկա, իսկ Crashlytics-ի stack trace-ը ցույց է տալիս obfuscate արված class-ների անուններ։
Ինչպես լուծել
Վերարտադրեք լոկալ npx react-native run-android --mode release-ով և կարդացեք adb logcat-ը native exception-ի համար։ Սովորական պատճառներն են՝ R8-ը հեռացնում է class-եր, որոնք native SDK-ն բեռնում է reflection-ով, բացակայում է build-time environment արժեք, կամ native գրադարանը բացակայում է CPU-ի որևէ architecture-ի համար։ Ավելացրեք SDK-ի փաստաթղթավորված keep rule-երը proguard-rules.pro-ում, համոզվեք, որ release build-ը ստանում է ճիշտ environment config, և որ mapping ֆայլերը upload են լինում Crashlytics, որպեսզի trace-երը դառնան ընթեռնելի։ Ապա CI-ում ավելացրեք release variant-ի ավտոմատ smoke test, որպեսզի այս տեսակի bug-երը բռնվեն նախքան tester-ները կտեսնեն։
Արագ ուղեցույց
- Գործարկել Android release build-ը լոկալ
npx react-native run-android --mode release- Reset անել Metro cache-ը
npx react-native start --reset-cache (Expo: npx expo start -c)- Բացել React Native DevTools-ը
Metro-ի terminal-ում սեղմեք j- Ստուգել լոկալ toolchain-ը
npx react-native doctor- Համաձայնեցնել Expo package-ների version-ները
npx expo install --check- Վերագեներացնել native թղթապանակները (Expo)
npx expo prebuild --clean- Տեղադրել iOS pod-երը
cd ios && bundle exec pod install- Մաքրել Android build-ի արդյունքները
cd android && ./gradlew clean- Ցույց տալ միայն Android-ի սխալները
adb logcat *:E- Պլանավորել upgrade-ի diff-ը
react-native-community.github.io/upgrade-helper
Իմ իրական նախագծերում
- Ես կառուցել եմ 5 React Native հավելված (ռեստորանային պատվերներ, կենդանիների խանութ, մարզասրահ, սրճարանի լոյալություն, ներդրումներ) ընդհանուր ներքին template-ի վրա՝ անցնելով RN 0.81-ից 0.86։
- Ամենանոր սուրճի պատվերների հավելվածն աշխատում է RN 0.86-ով՝ New Architecture-ով և Hermes-ով, Reanimated 4.5-ով և Zustand-ով․ adapter layer-ը normalise է անում backend-ի պատասխանները, այնպես որ վերանվանումը երբեք չի դիպչում էկրանին։
- Իմ ղեկավարած ռեստորանային հավելվածը ներառում է custom native Android մոդուլ տարածաշրջանային վճարային պրովայդերի համար, ինչպես նաև Remote Config force update, փոխարկվող API base URL և retry policy, որը կրկնում է միայն idempotent հարցումները։
- Մարզասրահի անդամների հավելվածն օգտագործում է VisionCamera՝ QR check-in-ի համար, և պլանավորված push արշավներ՝ փաստաթղթավորված release process-ով։
Հարցեր և պատասխաններ
Q1Ինչո՞վ է React Native-ը տարբերվում hybrid WebView հավելվածից։
Hybrid հավելվածը, ինչպիսիք են Cordova-ն կամ Capacitor-ը, HTML-ը և CSS-ը render է անում WebView-ի ներսում, այնպես որ ամբողջ UI-ը վեբ էջ է։ React Native-ը render է անում իրական native կոմպոնենտներ՝ View-ն դառնում է UIView կամ Android ViewGroup, TextInput-ը պլատֆորմի տեքստային դաշտն է, scroll-ն ու ժեստերը native են։ JavaScript-ն աշխատում է Hermes-ում և նկարագրում UI-ը, իսկ native կողմը նկարում է այն։ Ահա թե ինչու RN հավելվածները զգացվում են native և ինտեգրվում են accessibility-ի, ստեղնաշարերի և համակարգի վարքագծի հետ։ Trade-off-ն այն է, որ չեք կարող ուղղակիորեն վերաօգտագործել վեբ DOM գրադարանները, և որոշ հնարավորություններին պետք են native մոդուլներ։
Q2Բացատրեք New Architecture-ը պարզ բառերով։
Նախկինում JavaScript-ը և native կոդը խոսում էին ասինխրոն bridge-ի միջոցով, որը յուրաքանչյուր հաղորդագրություն serialize էր անում JSON-ի, ինչը դանդաղ էր անիմացիաների և մեծ ցուցակների համար։ New Architecture-ը հեռացնում է այդ bridge-ը։ JSI-ը թույլ է տալիս JavaScript-ին ուղղակիորեն և սինխրոն կանչել C++ օբյեկտներ։ Fabric-ը նոր C++ renderer է, որն աջակցում է concurrent React-ին և layout-ի սինխրոն չափմանը։ TurboModules-ը native մոդուլները բեռնում է lazy կերպով, իսկ Codegen-ը TypeScript spec-երից գեներացնում է type-safe glue։ Այն default է 0.76-ից և միակ ճարտարապետությունը՝ 0.82-ից, ուստի գործնականում հիմնական խնդիրն այն աջակցող գրադարաններ ընտրելն է։
Q3Ինչպե՞ս եք կառուցում React Native նախագիծը երկարակյաց պրոդուկտի համար։
Ըստ feature-ի՝ հստակ ընդհանուր layer-ներով։ Յուրաքանչյուր feature թղթապանակ պարունակում է իր էկրանները, hook-երը և կոմպոնենտները։ Ընդհանուր API layer-ին են պատկանում HTTP client-ը, auth header-ները, token refresh-ը, timeout-ները և adapter-ները, որոնք backend-ի payload-ները վերածում են հավելվածի տիպերի։ Store-երը պահում են session-ը, զամբյուղը և կարգավորումները․ էկրանները միայն կարդում են store-երը և կանչում action-ներ։ UI-ը կառուցված է design token-ներ օգտագործող մի քանի բազային կոմպոնենտից, այնպես որ dark mode-ը և rebrand-ները էժան են։ Navigation-ը, deep link-երը և push-ի մշակումն ապրում են մեկ app թղթապանակում։ Սա փոփոխությունները պահում է տեղային և թույլ է տալիս մի քանի ծրագրավորողի կամ AI agent-ի աշխատել առանց իրար խանգարելու։
Q4Ինչպե՞ս եք բարելավում դանդաղ ցուցակի արագագործությունը։
Նախ չափեք React Native DevTools profiler-ով իրական միջին կարգի Android հեռախոսի վրա։ Հետո անցեք FlashList-ի կամ կարգավորված FlatList-ի, երբեք ScrollView map-ով։ Տարրերին տվեք կայուն key-եր, memoize արեք row կոմպոնենտը և renderItem-ը պահեք էժան՝ առանց ամբողջ տվյալների inline դասավորման կամ ֆորմատավորման։ Փոխանցեք միայն այն props-ը, որոնք պետք են row-ին, որպեսզի չկապված state-ի փոփոխությունները re-render չանեն յուրաքանչյուր row։ Նկարները փոքրացրեք սերվերում և օգտագործեք cache անող image կոմպոնենտ։ Pagination արեք API-ից և ծանր անիմացիաները տեղափոխեք Reanimated, որպեսզի դրանք աշխատեն UI thread-ի վրա։
Q5Expo, թե՞ bare React Native․ ո՞րն եք խորհուրդ տալիս։
Նոր հավելվածների մեծ մասի համար խորհուրդ եմ տալիս Expo, և React Native թիմն էլ նույնն է անում։ Ստանում եք սպասարկվող մոդուլներ, development build-եր, config plugin-ներ native փոփոխությունների համար, EAS Build և Submit, ինչպես նաև OTA թարմացումներ, ինչը վերացնում է setup-ի և upgrade-ի ցավի մեծ մասը։ Expo-ն ձեզ չի կտրում native կոդից․ կարող եք ավելացնել custom մոդուլներ և config plugin-ներ։ Bare-ն իմաստ ունի, երբ արդեն ունեք native-ով ծանր template, պետք են անսովոր SDK-ներ, որոնք դժվար է plugin-ների մեջ փաթաթել, կամ թիմ, որն ուզում է ուղղակի վերահսկողություն Xcode և Gradle նախագծերի վրա։ Ամեն դեպքում dependency-ները թարմ պահեք։
Q6Ինչպե՞ս եք անվտանգ մշակում նույնականացումը մոբայլ հավելվածում։
Օգտագործեք կարճաժամկետ access token-ներ refresh token-ով, որոնք backend-ը տալիս է գաղտնաբառով, OTP-ով կամ social sign-in-ով մուտքից հետո։ Token-ները պահեք iOS Keychain-ում կամ Android Keystore-ում, ոչ թե AsyncStorage-ում։ API client-ը կցում է access token-ը, 401-ի դեպքում մեկ անգամ refresh է անում և refresh-ի ընթացքում զուգահեռ հարցումները հերթագրում, իսկ եթե refresh-ը ձախողվում է, մաքուր logout է անում։ Root navigator-ը session-ի վիճակից կախված փոխարկում է auth և main stack-երի միջև։ Երբեք private key-եր կամ գաղտնիքներ մի ներդրեք հավելվածում, OTP-ը rate-limit արեք սերվերում և աջակցեք հաշվի ջնջմանը հավելվածի ներսում, ինչը պահանջում է Apple-ը։
Սենիոր մակարդակի հարցեր
S1Ինչպե՞ս կկիսեիք կոդը React Native հավելվածի և React web հավելվածի միջև։
Նախ կիսեք այն, ինչը pixel-ներ չունի։ Monorepo-ում ես API type-երը, HTTP client-ը, adapter-ները, validation schema-ները, domain logic-ը և store-երը դնում եմ package-ների մեջ, որոնք երկու հավելվածներն էլ import են անում․ դրանք մաքուր TypeScript են և հեշտ են թեստավորվում։ UI-ը առանձին որոշում է։ React Native Web-ը կարող է նույն component-ները render անել web-ում, ինչն արդարանում է ներքին գործիքների կամ պարզ էկրանների համար, բայց marketing կայքերը և SEO էջերը սովորաբար ուզում են native web component-ներ և server rendering։ Design token-ները լավ միջին տարբերակ են․ մեկ token-ի աղբյուր, որը սնում է և՛ CSS variable-ները, և՛ native theme object-ը։ Trade-off-ներն են tooling-ի բարդությունը՝ Metro-ն, Next.js-ը և TypeScript project reference-ները բոլորը պետք է resolve անեն package-ները, և coupling-ը․ shared package-ի փոփոխությունն այժմ պահանջում է երկու հավելվածների թեստավորում, ուստի shared շերտը պետք է ունենա իր սեփական թեստերը և հստակ versioning։
S2Նախագծեք offline-first պատվերի հոսք mobile հավելվածի համար։
Առանձնացրեք ընթերցումները գրառումներից։ Ընթերցումները գալիս են լոկալ cache-ից՝ storage-ում persist արված TanStack Query կամ SQLite՝ ավելի մեծ տվյալների համար, ցուցադրվում են անմիջապես timestamp-ով և թարմացվում, երբ network-ը վերադառնում է։ Գրառումները դառնում են command-ներ լոկալ outbox-ում․ յուրաքանչյուր պատվեր ստանում է client-ի կողմից գեներացված idempotency key, պահվում է լոկալ, ցուցադրվում որպես pending և ուղարկվում, երբ կապը թույլ է տալիս։ Սերվերը պետք է key-ը համարի unique, որպեսզի timeout-ից հետո retry-ը վերադարձնի սկզբնական պատվերը, այլ ոչ թե ստեղծի երկրորդը։ Conflict-ները պահանջում են բիզնես կանոններ, ոչ թե տեխնիկական մոգություն․ եթե ապրանքը սպառվել է կամ գինը փոխվել է, սերվերը մերժում է հստակ պատճառով, և հավելվածը հարցնում է օգտատիրոջը։ Trade-off-ներ․ client-ի ավելի մեծ բարդություն, լոկալ schema-ի migration-ներ և զգույշ UX, որպեսզի օգտատերերը հասկանան, թե ինչն է հաստատված, իսկ ինչը՝ pending։
S3Ինչպե՞ս եք արդի պահում ընդհանուր template-ի վրա հիմնված մի քանի հավելված։
Template-ին վերաբերվեք որպես սեփական versioning ունեցող product-ի։ Shared կոդը՝ API client, auth, theme system, push, force update, տեղափոխվում է package-ների կամ հստակ նշված core թղթապանակի մեջ, որը հավելվածներն ուղղակիորեն չեն խմբագրում․ հավելվածին հատուկ կոդը ապրում է այլ տեղում։ React Native-ի upgrade-ները նախ արվում են template-ում՝ մեկ minor version միաժամանակ, Upgrade Helper-ով և checklist-ով, որը ներառում է յուրաքանչյուր dependency-ի New Architecture-ի համատեղելիությունը։ Այնուհետև յուրաքանչյուր հավելված փոփոխությունը վերցնում է branch-ում, գործարկում իր release build-ը և smoke test-երը և ship անում TestFlight-ի և internal track-ի միջոցով։ Trade-off-ը կարգապահություն ընդդեմ ազատության է․ որքան շատ է հավելվածը fork անում template-ը, այնքան թանկ է դառնում յուրաքանչյուր upgrade, ուստի ես թիմերին մղում եմ fix-երը հետ ուղարկել core, այլ ոչ թե patch անել լոկալ։
S4Ե՞րբ կընտրեիք native development-ը React Native-ի փոխարեն նոր նախագծի համար։
Երբ product-ի արժեքը պլատֆորմի մեջ է։ Օրինակներ՝ ծանր real-time գրաֆիկա, AR, բարդ background audio կամ Bluetooth աշխատանք, խորը widget և watch ինտեգրացիաներ, կամ հավելվածներ, որտեղ էկրանների մեծ մասը custom native փորձառություններ են՝ քիչ ընդհանուր տրամաբանությամբ։ Նաև երբ կազմակերպությունն արդեն ունի ուժեղ առանձին iOS և Android թիմեր․ նրանց React-ի վրա ստիպելը ավելացնում է ծախս՝ առանց օգուտի։ React Native-ը հաղթում է, երբ հավելվածի մեծ մասը ֆորմեր, ցուցակներ, commerce և content է, երբ թիմը գիտի React, և երբ iOS-ը և Android-ը պետք է նույն feature-ները ship անեն միաժամանակ։ Կա նաև hybrid ճանապարհ՝ native հավելված, որը որոշ էկրանների համար embed է անում React Native, կամ React Native հավելված՝ մի քանի native էկրաններով։ Ազնիվ պատասխանը cost model է՝ թիմի հմտություններ, feature parity-ի կարիքներ, performance-ի ռիսկեր և երկարաժամկետ սպասարկում։
Բառարան
- Hermes
- JavaScript engine, որը React Native-ը օգտագործում է default-ով․ օպտիմալացված է mobile-ի համար՝ build-ի ժամանակ compile արված bytecode-ով։
- JSI
- JavaScript Interface․ C++ API, որը թույլ է տալիս JavaScript-ին ուղղակիորեն և սինխրոն կանչել native object-ներ՝ առանց JSON bridge-ի։
- Fabric
- New Architecture-ի renderer-ը, որը UI tree-ն կառուցում է C++-ում և աջակցում է concurrent React-ին։
- TurboModule
- New Architecture-ի native module, որը բեռնվում է lazy և տիպավորվում Codegen spec-ի միջոցով։
- Codegen
- Build-time գործիք, որը տիպավորված JavaScript spec-երը վերածում է C++ և պլատֆորմային interface-ների native կոդի համար։
- Shadow tree
- UI tree-ի Fabric-ի C++ պատճենը, որն օգտագործվում է layout հաշվարկելու համար՝ նախքան փոփոխությունները կհասնեն իրական native view-երին։
- Yoga
- Cross-platform layout engine, որն իրականացնում է Flexbox-ը React Native component-ների համար։
- Metro
- JavaScript bundler և development server, որը ձեր կոդը մատուցում է հավելվածին և ապահովում Fast Refresh-ը։
- Worklet
- Փոքր JavaScript function, որը Reanimated-ն աշխատեցնում է UI thread-ում, որպեսզի անիմացիաները սահուն մնան, երբ JavaScript-ը զբաղված է։
- Config plugin
- Expo function, որը prebuild-ի ժամանակ խմբագրում է native project-ի ֆայլերը, որպեսզի native կարգավորումը մնա վերարտադրելի։
Շարունակեք սովորել
Պրոդուկտի գաղափար ունե՞ք։Եկեք ստեղծենք այն։
Պատմեք ձեր գաղափարի, պրոդուկտի կամ թիմի մասին։ Սովորաբար պատասխանում եմ մեկ աշխատանքային օրվա ընթացքում։