Getting Started with React Native in 2020

I've been doing React Native for over 4 years. It is amazing how much it has improved, but also how much was there from the start. The React-ive UI development experience is still way ahead of the standard approaches on native platforms (SwiftUI and Jetpack Compose are promising). But things have changed. This article is my suggestions on how to set up a new project (as of 0.62). It will probably make sense for a small team of 1-10(?) developers. For larger teams different approaches may make sense. I also don't use Expo which is probably a better way to start for complete beginners. I've done a bunch of native mobile development on both platforms previously so Expo personally never made much sense, but it may for you.

To start with follow the official guide. NB following the CLI Quickstart not Expo. React Native (especially with the 'lean core' effort) is like React on the Web: it is not a complete solution, you will need to use some other packages to get stuff done. But to start with get the basics set up, including the new Flipper debugger. The first time is a bit slow (e.g. including things like Cocoapods setup for iOS native code).

I'm assuming you've now got the basic app running. The live/hot reload experience has improved massively as of 'fast refresh' and, outside of Flutter, is still a pretty amazing/impressive feature. You should play around a bit with that, Flipper for debugging and quickly review the docs.

PS You can create projects using templates. When I last tried the TypeScript one was out of date, but may have been updated by now. I'd expect it to continue to lag a bit.

Tooling

Let's install some tooling. It is 2020. Not using TypeScript even for anything other than a tiny JS project seems foolish. Here are the basics I tend to use (this includes some @types for packages we'll install later).

yarn add -D @types/lodash @types/react @types/react-native @types/react-native-vector-icons @types/react-navigation ts-jest typescript husky lint-staged prettier

Set up a tsconfig.json. Something like the below is okay to start:

{
  "compilerOptions": {
    "target": "es2015",
    "jsx": "react",
    "noEmit": true,
    "moduleResolution": "node",
    "strictNullChecks": true,
    "allowSyntheticDefaultImports": true
  },
  "exclude": ["node_modules"]
}

You can set up prettier to run with git hooks. I configure as prettierrc.js:

module.exports = {
  jsxBracketSameLine: true,
  semi: false,
}

You should stick fairly closely to defaults, but semicolons are ugly(!)

Now rename a file with .tsx and restart the bundler to check TypeScript is working.

Navigation

For a non trivial app you will want navigation. react-navigation is the overwhelming favourite in the React Native world. They have recently split things up a bit and changed the APIs to be component based (in version 5) so installing it requires adding a lot of packages but their guides are good. Follow that, the (at time of writing) full install is:

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

At this point it is probably worth creating an src folder and subfolders to stick code in. React Native is very unopinionated on how you structure stuff. Usually a screens and components subfolder is decent way to start.

So you've now gotten TypeScript and navigation.

Core Libraries

I suggest installing:

yarn add lodash react-native-linear-gradient react-native-snap-carousel react-native-splash-screen react-native-vector-icons rxjs uuid @react-native-community/async-storage react-native-svg

You will also need to a cocoapods install aftewards:

cd ios
pod install

with possible excpetion of rxjs and the icons you'll probably want these on nearly any project. Several of these have at least some manual setup for native parts but you can likely ignore until you actually need it.

You will want to add something like this to wrap storage (I should really figure out which npm package does this well).

import AsyncStorage from '@react-native-community/async-storage'

export async function getItem<T>(key: string): Promise<null | T> {
  const raw = await AsyncStorage.getItem(key)
  try {
    if (raw) {
      return JSON.parse(raw)
    } else {
      return null
    }
  } catch (ex) {
    return null
  }
}

export async function setItem<T>(key: string, item: T): Promise<boolean> {
  await AsyncStorage.setItem(key, JSON.stringify(item))
  return true
}

State

This gets controversial. For a while everyone seemed to choose Redux. But now we've all 'realised' it is verbose, tedious and actually quite hard to change (as you end up with a bunch of reducers aligned with how your app used to be structured). My personal favourite for a moderately substanial project is mobx-state-tree:

yarn add mobx mobx-state-tree mobx-react-lite

This guide shows how you can set it up, but the details are likely to change so check the website. I think mobx-state-tree is pretty amazing, as it allows you to create state outside of views, in a clear, concise and easy to change way, with great typescript support. It is batteries included: async updates, selectors/derived views and more are included out of the box. And with mobx you can performantly hook up in a reactive way to your views.

For simple projects you can probably get away without anything special (just standard React stuff, perhaps including some shared state via Context). immer is also pretty amazing as a small drop in utility, allowing you to write idiomatic TypeScript code yet under the hood get updates in an immutable way, playing nicely with shallow diffing for performance and making debugging easier.

Next Steps

I'd suggest spending some time learning reanimated. This allows you to create UI thread animations and gestures. The documentation is pretty bad, so you will likely want to start with William Candillon's course or Youtube videos.

You may want to look at UI frameworks. I personally like React Native Paper but you may also want to just create things out of the box with React Native for a fully custom look and feel. One of the things it does really well is exposing very flexible components allowing you to do exactly that.

Assuming you are developing for both platforms do try to run it on both. For a while Android was sufficiently far behind iOS that an Android-first development process made sense in the same way that mobile-first works for web. Generally the simulators/emulators work well and are less disruptive to flow/concentration that running on actual devices all the time. But you do need to check things there, especially around keyboard behaviour.

At the moment React Native is a good choice even for single platform development. Probably when SwiftUI and Jetpack Compose mature this will be less true.

Creating native modules is also worth learning about. It is a bit tedious/verbose adding the integration code and forces you to write at least some Objective-C 😔 code but will eventually become important. I'd suggest avoiding native UI components unless absolutely necessary. They are especially tedious (with view managers and huge differences across platforms). With reanimated you can likely do most things anyway.