React Native - Setup application - TypeScript, NativeWind, Jest, Cypress, SecureStore, TanstackQuery, Toastify



Application from scratch - Setup Part 2a. React Native
At the end of this article you'll have a fully functional React Native application with type safety, routing with tabs, testing, formatting, linting, local storage, styling, layouting utils, state management both sync and async and side effects handling.
All code is open source in this repository.
To get access to the final template without following all the below steps you can cheat by running:
git clone --depth 1 -b v0.0.1 https://github.com/Tokels/react-native-template.git
We'll work according to this workflow (GitHub organization, GitHub Projects, Project Boards etc.). Let's continue the setup with setting up a React Native project from scratch. You can also visit this project board where you will be able to see all these steps and the pull requests belonging to each todo-item.
We will continue with this workflow for each step:
- Add item to "Todo - "
- Add description
- Assign item to developer
- Convert to issue - choose repository where issue belongs too
- Add label/s
- Create branch
- Do what you need to do for the issue
- Add, commit and push
- Merge with main, later when CD is setup we will only merge with main if the preview build is successful
- Securely delete branch
Step 1. Setup Expo App (TS Template)
Expo allows you to quickly start developing your app without worrying about device-specific setup or native code dependencies.
npx create-expo-app --template
- When prompted to choose a template, select the
Navigation (TypeScript)
template.
Step 2. Delete template code
I kept it simple, view commit
Step 3. Setup ESLint & Prettier
- ESLint and Prettier configured according to This article
- Add scripts to package.json:
"lint": "npx eslint . --ext .js,.jsx,.ts,.tsx",
"lint-fix": "npm run lint -- --fix",
"format": "prettier --check ./",
"format-fix": "npx prettier --write ./"
npm run lint-fix && npm run format-fix
- Edit template code to fix eslint errors
My .eslintrc.js ended up looking like this
Step 4. Setup Jest
Setup Typescript with Jest according to This article
Followed by the steps in This documentation
To see what I did, (view commit)[https://github.com/Tokels/react-native-template/commit/10c6940bcfa36d2ce94ff0fc72ac87379d554b34]
Step 5. Setup Cypress
Configuration Documentation And how to use Cypress with TS
To see what I did, view commit
Step 6. Move to Src folder
As your project grows, it can be helpful to move all of the directories containing application code into a single src directory. Expo supports this according to this doc
I did it like this, view commit
I later noticed that I didn't change the pointer to the asset folder in app.json, I fixed it here
Step 7. Setup CI and Step 8. Setup CD
Using GitHub actions, follow This article
- Typo in example for CD in article,
((
and))
should be{{
and}}
- If you have subdirectory in root, follow This stack
- Make sure to create an EXPO_TOKEN, Described in this doc
I also created a preview when a pull request is made, according to This doc by expo.
I you get an error like:
Error: Generating a new Keystore is not supported in --non-interactive mode
Simply run npx eas build --platform android
in your wdir and Expo will generate the Keystore for you. You can then rerun the job.
View my commit for CI View my commit for CD
Check: did you create an eas.json file?
Step 8. Setup NativeWind (tailwind)
yarn add nativewind
yarn add --dev tailwindcss
npx tailwindcss init
- Add to contents array
'./app/**/*.{js,jsx,ts,tsx}', './components/**/*.{js,jsx,ts,tsx}'
in tailwind config file - Add to plugins array
'nativewind/babel',
in babel config file - Add
/// <reference types="nativewind/types" />
toglobal.d.ts
file - Add to your top-level component, e.g. index.tsx or app.tsx (this will be deprecated in NativeWind v4)
import { NativeWindStyleSheet } from "nativewind";
NativeWindStyleSheet.setOutput({
default: "native",
});
There's a bug not yet fixed with tailwindcss that will give you this error:
Use process(css).then(cb) to work with async plugins
I locked the version of tailwindcss to 3.2.2, solved in This issue
This is what I ended up doing, view commit
Step 9. Setup SecureStore
Setup SecureStore, recommended for sensitive data by Expo in This documentation.
Step 10. Setup Toastify
We'll use Toastify to handle messages to the user. This includes error messages and successful messages. We'll use the default styling for now.
To simplify the usage of Toastify we'll create a custom Context Provider and pass a setter to the children. This setter will trigger the toast.
Click here to read more about this powerful context provider
My build was failing because toastify uses dependencies that it doesn't install itself. I installed these manually, See commit After installing these I could successfully preview my build and could then merge with main.
Step 11. Setup TanStack Query
Powerful asynchronous state management
yarn add @tanstack/react-query
yarn add --dev @tanstack/eslint-plugin-query
- Initialise QueryClient
- Wrap app with QueryClientProvider passing queryClient as client
Here's my commit for the TanStack setup. I also made a commit for an example on how to use TanStack Query using a Provider that wraps the components, making the components be able to perform complex task without handling the logic. You can see it here.
Step 12. Adapt Design for Side Effects
Side Effects
refer to changes that a function or an expression makes to the state of the program or the environment outside of its own scope. Network Request
are an example of a side effect where it's important to inform the user what is happening in case the request takes too long.
You can read more about side effects here. In the article I explain about different side effects, and how we can adapt to our side effects in terms of design.
So far in our application we've already setup Toastify which handles side effects, but what about loading spinners when the user is waiting? For this step we'll setup a provider for the loading spinner which we can wrap around whatever element we need. So instead of doing this:
{
isLoading ? <ActivityIndicator /> : <YourComponent />;
}
We'll be doing this:
<ActivityIndicatorProvider>
<YourComponent />
<ActivityIndicatorProvider />
View my commit to get access to the Provider.
Step 13. Add a ThemeProvider
I read this quick article and got some inspiration of how I want this application to handle theme styling. This is important because in the beginning of a project the style might change constantly. Creating a good framework of testing different colours are essential, a simple setup will reduce so much time spent on styling later on.
Unfortunately, NativeWind doesn't support customed styles.css
yet, however, they are releasing it in v4, read docs. v4 is up for testing for npm
, but I prefer to wait until the final release since it will happen soon.
Meanwhile, I'll keep the setup as in this commit and will create a separate ticket to upgrade NativeWind once final v4 release.
Step 14. Create a Reusable layout component
Read more about reusable layout components and why they are awesome. I have also provided a smart layout component in that article, or you can view my commit.
Step 15. Git Tags
I will add a milestone commit where I will add some description in the main Readme.md because now we have a fully functional template for a React Native app with type safety, routing with tabs, testing, formatting, linting, local storage, styling, layouting utils, state management both sync and async and side effects handling.
To get access to the final template simply run:
git clone --depth 1 -b v0.0.1 https://github.com/Tokels/react-native-template.git
To add authentication to your application, continue by reading this article.