Project is generated by
//TODO:
- Add React Navigation
- Add Styled Components
- Add Jest
Please read High-level Architecture to see the context of a React Native App in the RTP landscape.
This repository is an example of React Native Application. Use this template when you start developing new app.
This repository is owned by RTP Enablement team
Fill in here your application purpose, and it's main functionalities. Also insert the link to your architecture from confluence.
Please make sure that you have installed
- React Native CLI
- React Native.
- NPM (Node Package Manager)
-
npm install npm@latest -g
-
- Yarn
-
npm install -g yarn
-
- NPM (Node Package Manager)
- Follow React Native guidelines to configure your development environment for both iOS and Androd;
- Install dependencies with
yarn
; - Launch metro server with
yarn start
; - Choose platform you want to work with by running:
yarn ios
;yarn android
(Android requires to launch an emulator or connected device beforehand);
react-native-template
├──android - android project;
├──ios - ios project;
├──e2e - E2E tests;
└──src - source code;
├──components - common components for all screens;
├──enums - common enums for all screens and components;
├──hooks - common hooks for all screens and components;
├──interfaces - common interfaces for all screens and components;
├──localization - common interfaces for all screens and components;
│ ├──context - context that contains translations for the current language;
│ └──locales - translations for different languages, grouped by namespace;
├──screens - all application screens;
├──store - redux store for the app;
├──test - setting up common mocks for tests;
├──app.tsx - entry point;
└──routes.tsx - all navigation routes for the app;
component
├──component.tsx - component code;
├──component.styles.ts - component style sheet;
├──component.hooks.ts - component hooks;
├──component.hooks.spec.ts - hooks test;
├──component.spec.ts - component test (with snapshot and functional test);
└──component.story.ts - component story to showcase its features
If a component gets big and complex consider:
- Decompose the component into smaller components
- If some parts are reusable across other components, extract them to the root
components
folder; - If these parts are specific to this component, consider creating
components
folder inside and place those components there. They should also follow the component structure rules;
- If some parts are reusable across other components, extract them to the root
- Create dedicated hook file, to simplify render function. By moving state and functions that operate with state or redux, you can see how component file becomes more about its structure;
- Do we have a group of components that serve the same purpose, consider grouping them in a dedicated folder (e.g.:
components/cards
for all card components)
When testing components:
- Mock dependencies (don't retest other components/hooks);
- Make snapshots for props variations;
- Test firing events at your component (e.g.: press, type, scroll);
When testing hooks include testing not only functions and state, but also effects.
you can check test examples in src/screens/todo
You can store all text labels in src/localization/locales
folder.
common
folder is mandatory to have.
However, you can create more and register those files in src/localization/context/localization-data
.
This will help to reduce file size and manage translations more easily.
To use translations in a component or a hook call useLocalization
.
Example:
const MyComponent = () => {
const { t } = useLocalize();
return <Text>{t('translation-key-from-json')}</Text>;
};
By default t('key')
picks up translation from the common
folder.
If you want to use another folder, then prefix key with folder-name:
.
That allows you to use translations from different folders.
Example:
const MyComponent = () => {
const { t } = useLocalize();
return (
<>
<Text>{t('common-translation-key')}</Text>
<Text>{t('folder-name:folder-specific-translation-key')}</Text>
</>
);
};
If you need to insert text inside your translation, use interpolation by wrapping text with {{parameter}}
Example translation file
{
"key1": "Hello",
"key2": "Hello {{name}}"
}
Code example
const MyComponent = () => {
const { t } = useLocalize();
return (
<>
<Text>{t('key1')}</Text>
<Text>{t('key2', { params: { name: 'My Name' } })}</Text>
</>
);
};
If you need to insert JSX inside your translation, use interpolation by wrapping text with <parameter>Some text</parameter>
Example translation file
{
"key1": "Hello",
"key2": "Hello <name>My name</name>"
}
Code example
const MyComponent = () => {
const { tJSX } = useLocalize();
return (
<>
<Text>{t('key1')}</Text>
<Text>
{tJSX('key2', {
components: { name: ({ children }) => <Text>{children}</Text> },
})}
</Text>
</>
);
};
Create a .env
file in the root and fill like this:
MY_ENV=my-env
Then you need to declare your variables in the file src/types/env.d.ts
:
declare module '@env' {
//...
export const MY_ENV: string;
}
Code example:
import { MY_ENV } from '@env';
console.log(MY_ENV); // my-env
Metro caches env variables. If you want to change a variable you will need to run the following command after changes:
yarn start --reset-cache
Then you can run yarn ios
or yarn android
with updated env variables.
Download google-services.json and replace it with the file with the same name in the folder android/app.
More info here.
Download GoogleService-Info.plist. Using Xcode, open the projects /ios/{projectName}.xcodeproj file (or /ios/{projectName}.xcworkspace if using Pods).
Right click on the project name and "Add files" to the project.
Select the downloaded GoogleService-Info.plist file from your computer, and ensure the "Copy items if needed" checkbox is enabled.
More info here.
To enable DebugView on Android you should launch an Android emulator and run the command adb shell setprop debug.firebase.analytics.app package_name
.
To disable you should run adb shell setprop debug.firebase.analytics.app .none.
.
To enable DebugView on iOS you should select the argument -FIRDebugEnabled
and discard -FIRDebugDisabled
in the Xcode (Choose the project -> Product -> Scheme -> Edit scheme -> Arguments). Then you need to build iOS project by yarn ios
.
Troubleshooting
If you don't see your iOS device in DebugView you may need to start the project through yarn start --resetCache
and build it in Xcode.
To send some analytics information to the Firebase Console you can use the method logEvent
with an event name and additional information:
const TodosListItem: FC<TodosListItemProps> = ({ todo, onSelect }) => {
const handlePress = async () => {
await analytics().logEvent('todo_click', { id: todo.id });
onSelect(todo.id);
};
return (
<TouchableOpacity style={styles.root} onPress={handlePress}>
<Text style={todo.isDone && styles.completedTodo}>{todo.text}</Text>
</TouchableOpacity>
);
};
To send crash reports to the Firebase Console you can use the method recordError
:
const CrashAppButton = () => {
const handleCrashApp = () => {
crashlytics().recordError(new Error('Crash by click on the crush button'));
};
return (
<View style={styles.container}>
<Button title="Crash App" onPress={handleCrashApp} />
</View>
);
};
More methods of Firebase Analytics and Crashlytics you can find here.
We use Detox to run E2E tests.
Firstly, you should setup Environments:
You need to create an emulator with the following parameters:
- Device: Pixel 5
- System image: Pie (Android 9.0)
- AVD Name: Pixel 5 E2E
Then check the Kotlin version: Open Android Studio > More Actions > SDK Manager > in the left sidebar click on 'Kotlin' > click 'install' if this button exists.
You should have iPhone 13 from the xCode by default.
Before running your tests you must compile the application. Run yarn e2e:ios:build
for iOS and e2e:android:build
for Android.
Then you can execute yarn e2e:ios:start
to run tests on iOS and yarn e2e:android:start
on Android.