Learn React Native

Initial configurations for RN repository

.prettierrc.js config

1module.exports = {
2    bracketSpacing: false,
3    jsxBracketSameLine: true,
4    singleQuote: true,
5    trailingComma: 'es5',
6    tabWidth: 2,
7    printWidth: 150,
8};

.eslintrc.js config

1module.exports = {
2    env: {
3        browser: true,
4        es6: true,
5        node: true,
6        'react-native/react-native': true,
7        'jest/globals': true,
8    },
9    extends: ['eslint:recommended', 'plugin:react/recommended', 'plugin:prettier/recommended', 'plugin:promise/recommended'],
10    settings: {
11        react: {
12            version: 'detect',
13        },
14        'import/resolver': {
15            'babel-module': {
16                root: ['.'],
17                alias: require('./aliases.json'),
18            },
19        },
20        'react-native/style-sheet-object-names': ['EStyleSheet'],
21    },
22    parserOptions: {
23        ecmaFeatures: {
24            jsx: true,
25        },
26        ecmaVersion: 8,
27        sourceType: 'module',
28    },
29    parser: 'babel-eslint',
30    plugins: ['react', 'react-native', 'jest', 'import'],
31    rules: {
32        eqeqeq: ['error', 'always'],
33        'import/no-unresolved': 2,
34        'no-console': 2,
35        'promise/prefer-await-to-then': 2,
36        'promise/no-nesting': 2,
37        'promise/prefer-await-to-callbacks': 2,
38        'react/jsx-curly-brace-presence': ['error', {props: 'never', children: 'ignore'}],
39        'react/prop-types': ['error', {ignore: ['navigation', 'theme']}],
40        'react-native/no-unused-styles': 2,
41        'react-native/split-platform-components': 1,
42        'react-native/no-inline-styles': 1,
43        'react-native/no-raw-text': 1,
44        'react-native/no-single-element-style-arrays': 1,
45        'require-await': 2,
46    },
47};

Implement eslint and prettier using pre-commit hook

  • Run command yarn add eslint-plugin-react eslint-plugin-react-native eslint-plugin-import eslint-import-resolver-babel-module husky lint-staged prettier eslint-plugin-prettier eslint-config-prettier eslint-plugin-jest eslint-plugin-promise babel-plugin-module-resolver --dev
  • Run command yarn husky install
  • Add the following config in package.json
1"lint-staged": {
2    "*.{js,jsx}": [
3        "prettier --write",
4        "eslint --fix",
5        "eslint",
6        "jest --bail --findRelatedTests"
7    ]
8}
  • Run command npx husky add .husky/pre-commit "yarn lint-staged"

Path alias

  • We already installed eslint-plugin-import, eslint-import-resolver-babel-module and babel-plugin-module-resolver packages.
  • The eslint config for path alias is already present in the above .eslinrc.js config.
  • So, just add following config in babel.config.js
1plugins: [
2    [
3        'module-resolver',
4        {
5            root: ['.'],
6            alias: require('./aliases.json'),
7        },
8    ],
9],
  • And create a aliases.json file in root directory which will contain all the path mappings in the following manner, where @components is the alias for the relative url "./app/components".
1{
2    "@components": "./app/components",
3}
  • For intellisense to work in vscode, we need to add a jsconfig.json in the root directory as well, which contains the mapping in the following manner:
1{
2    "compilerOptions": {
3        "baseUrl": ".",
4        "paths": {
5            "@components/*": ["./app/components/*"],
6        }
7    }
8}

Base packages to start with

  • Install following packages for implementing navigation. yarn add @react-navigation/native react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view @react-navigation/stack

  • Install following package for implementing scalable size units. yarn add react-native-extended-stylesheet

  • Install following package for showing various messages across the app. yarn add react-native-snackbar

  • Install following package for implementing state management library redux. yarn add redux react-redux

  • Install following package for persisting redux state and use aysncStorage as your default storage. yarn add redux-persist @react-native-async-storage/async-storage

  • Install following package for easing the process of making api request. yarn add axios

  • Install following package for implementing splash screen. yarn add react-native-bootsplash

  • Install following package for specifying prop-types of components. yarn add prop-types

  • Install following package for adding prop based dynamic styling. yarn add styled-components

  • Install all the above packages in single command. yarn add @react-navigation/native react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view @react-navigation/stack react-native-extended-stylesheet react-native-snackbar redux react-redux redux-persist @react-native-async-storage/async-storage axios react-native-bootsplash prop-types styled-components

  • Add the following config in package.json file

1"resolutions": {
2    "styled-components": "^5"
3}
  • Run command npx pod-install ios

Setup for tests

  • Run command yarn add @types/jest enzyme enzyme-adapter-react-16 jest-enzyme jest-transform-stub react-dom --dev
  • Create a dir named jest in the root of the project and a file inside jest dir with the name setup.js and add the following config in setup.js.
1import Enzyme from "enzyme";
2import Adapter from "enzyme-adapter-react-16";
3
4Enzyme.configure({ adapter: new Adapter() });
  • Add the following keys under jest object in package.json
1"jest":{
2    ...
3    "moduleNameMapper": {
4        ".+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "jest-transform-stub"
5    },
6    "setupFiles": [
7        "<rootDir>/jest/setup.js"
8    ],
9    "setupFilesAfterEnv": [
10        "./node_modules/jest-enzyme/lib/index.js"
11    ],
12    "testEnvironment": "jsdom"
13}

Final changes before starting the actual work.

  • Add import 'react-native-gesture-handler'; at the top of index.js file in the root of your project.
  • Create a dir named src in the root of your project.
  • Add the following key in aliases.json we created previously.
1"@src": "./src"
  • Add the following key under paths in jsconfig.json we created previously.
1"@src/*": ["./src/*"]
  • Within the src dir add a file navigation.js. This will be the file where we add all navigation details. Following is a boilerplate. Checkout React Navigation docs to understand the boilerplate.
1// LIBRARIES
2import React from "react";
3import {
4  createStackNavigator,
5  CardStyleInterpolators,
6} from "@react-navigation/stack";
7
8// SCREENS IMPORT
9import ExampleScreen from "@screens/ExampleScreen";
10
11const Stack = createStackNavigator();
12function ExampleApp() {
13  return (
14    <Stack.Navigator
15      headerMode="none"
16      screenOptions={{
17        gestureEnabled: true,
18        gestureDirection: "horizontal",
19        cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
20      }}
21    >
22      <Stack.Screen name="ExampleScreen" component={ExampleScreen} />
23    </Stack.Navigator>
24  );
25}
26
27export default ExampleApp;
  • <ins>Note</ins>: In the above snippet we see ExampleScreen. You can create any screen but make sure to implement it and add correctly the alias in aliases.json as well as jsconfig.json in order to run the app.
  • Replace the content of App.js in the root of your project with the following.
1// LIBRARIES
2import React from 'react';
3import {Platform} from 'react-native';
4import {NavigationContainer} from '@react-navigation/native';
5import {SafeAreaProvider} from 'react-native-safe-area-context';
6import EStyleSheet from 'react-native-extended-stylesheet';
7
8// APP SETUP
9import ExampleApp from '@src/navigation';
10
11EStyleSheet.build({$rem: Platform.OS === 'ios' ? 1.1 : 0.95});
12
13export default class App extends React.Component
14    render() {
15        return (
16            <NavigationContainer>
17              <SafeAreaProvider>
18                  <ExampleApp />
19              <SafeAreaProvider/>
20            </NavigationContainer>
21        );
22    }
23}

Adding support for tests

  • Create a dir named __mocks__ in your project's root dir.
  • Create a file named mock.js within the __mocks__ dir.
  • Add the following code in mock.js.
1import "react-native-gesture-handler/jestSetup";
2
3jest.mock("react-native-reanimated", () => {
4  const Reanimated = require("react-native-reanimated/mock");
5  Reanimated.default.call = () => {};
6  return Reanimated;
7});
8
9jest.mock("react-native/Libraries/Animated/src/NativeAnimatedHelper");
  • In package.json add the following line within setupFiles array under jest key.
1"<rootDir>/__mocks__/mock.js"
  • Once you are done with all the above configuration you can now run the app with either yarn ios or npx react-native run-ios for iOS build or yarn android or 'npx react-native run-android` for android build.

Setup for Redux

  • Create a dir named redux inside src dir we created above.
  • Under redux create two files reducers.js and store.js.
  • Add the below code in reducers.js.
1import { combineReducers } from "redux";
2const Reducer = combineReducers({});
3export const rootReducer = Reducer;
  • Add the below code in store.js.
1import { createStore } from "redux";
2import { rootReducer } from "./reducers";
3export default Store = createStore(rootReducer);
  • Now as and when we create new reducers we have to import it add it to combineReducers in reducers.js file.
  • Add following key in aliases.json we created previously.
1"@redux": "./src/redux"
  • Add following key in jsconfig.json we created previously.
1"@redux/*": ["./src/redux/*"],
  • Add following import statements in App.js of your root dir.
1import { Provider } from "react-redux";
2import Store from "@redux/store";
  • Add Provider and Store in App.js of your root dir as below.
1...
2<Provider store={Store}>
3    <NavigationContainer>
4        <SafeAreaProvider>
5            <ExampleApp />
6        </SafeAreaProvider>
7    </NavigationContainer>
8</Provider>
9...

Redux persist

  • For adding redux persist please follow the installation guide of the package here.
  • After adding redux persist your store.js under redux dir may look something like this.
1import { createStore } from "redux";
2import { persistStore, persistReducer } from "redux-persist";
3import AsyncStorage from "@react-native-async-storage/async-storage";
4import { rootReducer } from "./reducers";
5const persistConfig = {
6  key: "root",
7  storage: AsyncStorage,
8};
9const persistedReducer = persistReducer(persistConfig, rootReducer);
10export const Store = createStore(persistedReducer);
11export const Persistor = persistStore(Store);
  • And you App.js in your root dir may look like this.
1// LIBRARIES
2import React, { useEffect } from "react";
3import { Platform } from "react-native";
4import { NavigationContainer } from "@react-navigation/native";
5import { SafeAreaProvider } from "react-native-safe-area-context";
6import EStyleSheet from "react-native-extended-stylesheet";
7import Snackbar from "react-native-snackbar";
8
9// REDUX SETUP
10import { Provider } from "react-redux";
11import { Store, Persistor } from "@redux/store";
12import { PersistGate } from "redux-persist/integration/react";
13
14// APP SETUP
15import ExampleApp from "@src/navigation";
16
17EStyleSheet.build({ $rem: Platform.OS === "ios" ? 1.1 : 0.95 });
18
19const App = () => {
20  // Example of usage of snackbar
21  useEffect(() => {
22    Snackbar.show({
23      text: "Shows the snackbar when the component has loaded",
24      duration: Snackbar.LENGTH_SHORT,
25    });
26  }, []);
27
28  return (
29    <Provider store={Store}>
30      <PersistGate loading={null} persistor={Persistor}>
31        <NavigationContainer>
32          <SafeAreaProvider>
33            <ExampleApp />
34          </SafeAreaProvider>
35        </NavigationContainer>
36      </PersistGate>
37    </Provider>
38  );
39};
40
41export default App;
⌘F
    to navigateEnterto select Escto close
    Older
    Newer