BrilworksarrowBlogarrowTechnology PracticesarrowReact Native Best Practices

React Native Best Practices

Lavesh Katariya
Lavesh Katariya
August 31, 2023
Clock icon7 mins read
Calendar iconLast updated August 6, 2024
Banner-React Native Best Practices
Quick Summary:-We have identified 13 best practices in React Native that are essential for every React Native developer when developing an app.

What Does it Mean by Best Practices?

It goes in the coding world – there are no strict rules, but some guidelines (more like suggestions) that many coders tend to avoid while writing code. When you're first starting out, it can be tempting to skip over coding guidelines. After all, your code might work just fine without them. But as your codebase grows bigger, you'll start to realize that adhering to guidelines is essential for keeping your code healthy and maintainable.

There are several benefits that we have discussed in our Java blog; you can read our blog about the benefits of clean code and best practices.

Alright, let's get down to the main point. What are the React Native best practices? Well, they're basically a bunch of guidelines that you can follow to create a maintainable codebase. In this article, we'll go into more detail about these practices.

Best Practices in React Native

banner-image

1. Use TypeScript with Your React Native App

TypeScript is a statically typed programming language which means it requires explicitly defining the data types for variables, functions, and other elements. This not only leads to more reliable code but also helps developers catch bugs during the compilation process. Consider the following to calculate order price:

function calculateOrderPrice(order) {

  return order.price + 1200;

}

The current code works fine, but it doesn't tell us much about what properties the order object contains, which could lead further to a crash if we try to access a property that doesn't exist.

To prevent the crash and enhance readability, we can use TypeScript. TypeScript is a programming language that adds types to JavaScript. This means that we can specify the type of each property in the object, which will help us avoid errors.

interface Order {

  price: number;

  name: string;

  taxPercentage: number;

}




function calculateOrderPrice(order: Order) {

  const { price, taxPercentage } = order;

  const taxValue = price * taxPercentage;

  return price + taxValue;

}

Here is the same function, but now you and your editor are aware of the object properties and their types in code, which makes it easier to extend the functionality.

2. Functional Components over the Class Components

In React Native, you will have two main components:  Functional and Class components. But functional components are the way to go in React Native. They're simpler, more concise, and faster than class components. This makes them easier to read, write, and test. Plus, they can improve your app's performance.

If you're not sure what components are, they're functions that return React elements. So if you're looking for a way to improve your React Native code, use functional components over class components. They're the future of React Native development.

However, it's essential to note that there are still scenarios where class components may be necessary, particularly if you're working with older codebases or integrating with libraries that rely on class components. 

Class Component Example

import React, { Component } from 'react';




class ClassComponent extends Component {

  constructor(props) {

    super(props);

    this.state = {

      count: 0,

    };

  }




  incrementCount = () => {

    this.setState({ count: this.state.count + 1 });

  };




  render() {

    return (

      <View>

        <Text style={styles.h1}>Class Component</Text>

        <Text>Count: {this.state.count}</Text>

        <Button title='Increment' onPress={this.incrementCount}/>

      </View>

    );

  }

}


export default ClassComponent;

In this class component example, we're using the Component class from react to create a component. State is managed within the component's constructor, and the render method defines the component's UI.

Functional Component Example

import React, { useState } from 'react';




const FunctionalComponent = () => {

  const [count, setCount] = useState(0);




  const incrementCount = () => {

    setCount(count + 1);

  };




  return (

    <View>

      <Text style={styles.h1}>Functional Component</Text>

      <Text>Count: {count}</Text>

      <Button title='Increment' onPress={incrementCount}/>

    </View>

  );

};




export default FunctionalComponent;

In this functional component example, we're using the useState hook from react to manage state. The component is defined as a simple JavaScript function that returns JSX to render the UI.

3. Import your dependencies in order

When you have a bunch of imports in one file, it could be a headache trying to find that one specific import you need if you have not organized your imports properly. Therefore it is essential to order imports in a consistent way.  

At the same time, you should also ensure that the dependencies have a proper sequence of imports. If the order is not correct, it can affect how components behave and lead to bugs that are hard to find.

Here's an example of how you can organize your imports:

  1. External imports — react
  2. Internal imports, like relative paths — ../button
  3. In folder imports like ./styles.ts
  4. The imports may be sorted alphabetically in every group
  5. Every group must be divided by white space
import React from 'react';

import { TouchableOpacity, View } from 'react-native';

import { Button, Card } from '../components'

import { MainLayout } from '../layouts'

import { StyledCard } from './styles.ts'

You can use formatting tools like Eslint and Prettier to automate and enforce the correct import order to avoid such issues. 

4. Use Path Alias to avoid long imports

Path aliases are a way to create shorter and more meaningful import paths in your code. This can be helpful when you have a deep or nested folder structure, and it can make your imports easier to read and understand.

For example, instead of writing a long import like this:

import { IconButton } from '../../components/buttons';

import { CircleButton } from 'components/buttons';

OR

import { CircleButton } from 'buttons';

Here’s how to use path aliases in both TypeScript and React Native to create shorter and more meaningful import paths in your code.

Path Alias in TypeScript

  1. Create or update the tsconfig.json file in your project if it doesn't exist already.
  2. Set the baseUrl to . , which represents the root of the directory. This sets the starting point for all path aliases.
  3. Add path aliases to the paths object.

In this example, we have two path aliases defined:

// tsconfig.json

{

  "extends": "expo/tsconfig.base",

  "compilerOptions": {

    "strict": true,

    // Path alias config

    "baseUrl": ".",

    "paths": {

      // This needs to be mirrored in babel.config.js

      // Components is a directory with sub directories

      "components/*": ["src/components/*"],




      // We want to expose the exports of the buttons index file

      "buttons": ["src/components/buttons/index"]

    }

  }

}

 

Now, TypeScript will be able to understand and parse the following imports:

import { CircleButton } from "components/buttons"

import { CircleButton } from "buttons"

React Native Path Alias

First, install the babel-plugin-module-resolver as a developer dependency

yarn add --dev babel-plugin-module-resolver

npm install babel-plugin-module-resolver --save-dev

Now we can update the babel.config.js file to use the **module-resolver**plugin and point to our directories.

**// babel.config.js**

module.exports = function (api) {

  api.cache(true)

  return {

    presets: ["babel-preset-expo"],

    plugins: [

      [

        "module-resolver",

        {

          alias: {

            // This needs to be mirrored in tsconfig.json

            components: "./src/components",

            buttons: "./src/components/buttons",

          },

        },

      ],

    ],

  }

}

Responsive style properties in React refer to the use of functions to create an adaptive user interface or a layout that adjusts to various screen sizes and orientations. Developing a responsive React Native app can be done in multiple ways, and one of them is by using react-native-normalize. This handy library offers functions that help you create responsive layouts effortlessly.

5. Implement Crash Analytics Tools

Crash analytics tools are like your magic tools that keep an eye on your app 24/7. They do real-time monitoring to help you identify crashes and errors. These tools analyze the crash data and give you the lowdown on what's causing the chaos.

So, if you're in the development process, and suddenly, the app crashes out of the blue. With the implementation of crash analytics, you can easily find the root causes of these crashes.

There are a bunch of awesome crash analytics tools out there, like Sentry, Firebase, Crashlytics, and more.  They're like your trusty companions, helping you debug React Native app and rescue it from potential crashes.

6. Add Dependencies Wisely

Dependencies are external libraries or packages that provide specific functionalities and assist in improving code structure, reducing development time. They can significantly streamline the development process.

But if you add dependencies too many or outdated dependencies, your app’s performance might take a hit. Therefore, it’s all about finding a balance - use what you need to keep things running smoothly.

You can use npm-check package to check the health of all the packages used in your project; it will check outdated dependencies and flag any outdated or unused ones. 

Run the following command:

npm-check -u

7. Dynamic Styling with JS.

Styled-components let you use CSS styles in tagged template literals in JavaScript. This means instead of writing separate CSS files; you can write actual CSS code directly in your JavaScript files, making it easier to manage and encapsulate styles within individual components. In addition, you can achieve dynamic styling with styled components. 

Since your styles are written in JavaScript code, you can easily use variables, conditions, and component props to make your styles respond dynamically to changes in the application's state or user actions.

8. Cross-Platform Compatibility

Android and iOS have their own way of handling things like fonts, layout, and navigation. So, it's important to make sure your app is platform-agnostic, which means it can run on both platforms without any major changes.

This may require you to write platform-specific code for certain features. You can use libraries like such as  Platform.select or react-native-device-info to ensure the app shines on both platforms.

9. CI/CD Setup

CI/CD, or Continuous Integration and Continuous Deployment, is a set of practices that help developers deliver software more reliably and efficiently.

When you make a change to the codebase, CI/CD pipelines run tests and build your app to ensure that all checks are green before deploying the latest updates. This helps to prevent bugs and ensure that your app is always up-to-date.

By setting up the CI/CD pipeline in Github/Gitlab/Bitbucket and integrating EAS Build and EAS Submit into the CI/CD pipeline, you can save a lot of development time. 

banner-image

By doing so, you can automatically trigger a build whenever code is merged into the master branch or start the pipeline as soon as code is pushed to the master branch. 

Here’s how it works. 

EAS Build compiles your React Native codebase on Expo public servers into production builds for iOS and Android. It also handles signing the build—a digital signature from a developer that an app’s code hasn’t been augmented since it was last submitted, which Expo facilitates programmatically.

EAS Submit, meanwhile, enables developers to easily submit their app to the Play Store or App Store after it’s built

10. Leverage Expo CLI

Expo is a well-known framework or platform for building universal native apps for Android, iOS, and the Web using JavaScript and TypeScript. 

Typically, developing apps for iOS requires Xcode (Apple’s development environment), and Android apps require Android Studio. With Expo, you don’t need to set up these tools. 

To run your app on a device during development, you can use the Expo Go app. You can simply scan a QR code generated by Expo’s development server using the Expo Go app, and it will load and run your app on your device.

By using it, you can simplify the development process by offloading a lot of the underlying setup and configuration to Expo.

12. Use Expo Snack for Rapid Prototyping

Leverage Expo Snack when you have for prototyping and collaboration. Expo Snack is an excellent web-based editor for writing code quickly and creating interactive demos, all within your browser without any setup. You can also share your projects with your colleagues. Using it, you can rapidly prototype, debug isolated issues, and share code snippets. 

13. Use Expo Router 

Expo Router is a powerful file-based router for React Native and web applications. It simplifies navigation in your app. As a result, users can move smoothly between different parts of your UI. It also supports easy deeplinking, which means you can link directly to specific screens in your app. 

14. Smart Testing Strategies

Static Analysis

Before running your code, leverage static analysis tools Eslint and TypeScipt to catch common mistakes and enforce coding standards. This is a quick and easy way to ensure basic code quality.

Unit Testing

Unit tests focus on evaluating individual components or functions in isolation. This step is essential for confirming your app's logic. Popular tools like Jest enable you to write unit tests for React Native, allowing for component testing without rendering. You can also use snapshots to monitor changes over time.

Component Testing

Component testing examines components in isolation but with a setup closer to a real app environment compared to unit testing. Tools like Enzyme or React Testing Library help simulate user interactions with components and evaluate their output effectively.

Integration Testing

Integration tests assess how well multiple components function together. These tests are inherently more complex and may take longer to execute, but they are vital for confirming that integrated components operate as intended.

End-to-End (E2E) Testing

E2E tests replicate actual user scenarios from beginning to end. Automation tools like Detox or Appium facilitate user interaction simulations on real devices or emulators, testing the complete flow of your app, including its interactions with external services and APIs.

Conclusion

These React Native best practices can help you create a more maintainable, reliable, and performant app. By following these best practices, you can create an app that your users will love.

Looking to build a high-quality React Native app? Our React Native developers can help. We follow best practices and use cutting-edge tools to deliver top-notch mobile applications. Contact us today to discuss your project requirements and get started.

FAQ

React Native excels at developing cross-platform mobile applications with native-like performance. It's ideal for projects requiring rapid development, code reusability, and a large, active community. It's particularly well-suited for apps with complex user interfaces, smooth animations, and the need to reach both iOS and Android audiences with a single codebase.

React Native offers several key features that contribute to its popularity. It leverages React's component-based architecture for efficient UI development. Hot reloading enables rapid development cycles by instantly reflecting code changes in the app. Strong community support and extensive third-party libraries accelerate development. Additionally, React Native's ability to seamlessly integrate with native code provides flexibility for complex functionalities.

Several tools can optimize React Native app performance. The React Native Profiler helps identify performance bottlenecks. Using FlatList or SectionList for long lists significantly enhances scrolling performance. Optimizing images, minimizing re-renders, and leveraging native modules for computationally intensive tasks are crucial. Code splitting, lazy loading, and using Hermes as the JavaScript engine can further improve app speed.

React Native offers several options for navigation. React Navigation is a popular and feature-rich library providing stack, tab, and drawer navigators. It supports custom transitions, deep linking, and header customization. For simpler navigation needs, the built-in Navigator component can be used. Understanding the project's specific requirements and desired user experience is essential when choosing a navigation solution.

Lavesh Katariya

Lavesh Katariya

With over 8 years of experience in the MERN stack, I specialize in building robust and scalable web applications. Proficient in MongoDB, Express.js, React.js, and Node.js, my passion for clean code and innovative problem-solving ensures high-quality solutions.

You might also like

Get In Touch


Contact us for your software development requirements

Brilliant + Works

Hello, we are  BRILLIAN’S.Trying to make an effort to put the right people for you to get the best results. Just insight !

We are Hiring hiring-voice
FacebookYoutubeInstagramLinkedInBehanceDribbbleDribbble

Partnerships:

Recognized by:

location-icon503, Fortune Business Hub, Science City Road, Near Petrol Pump, Sola, Ahmedabad, Gujarat - 380060.

© 2024 Brilworks. All Rights Reserved.