10 Tips for Structuring a React Native Project

10 Tips for Structuring a React Native Project:

 

When starting a new project, there are plenty of choices to be made around code style, language, folder layout, and more. Consistency is the key for creating clean, maintainable codebases. Therefore once decided, you’d usually need to stick with these choices for a while.

Time and experience will teach you what works and what doesn’t. But what if you don’t have time? You can always use someone else’s experience.

Here are my top 10 tips for structuring a React Native project:

1. Use TypeScript

Yes, there is a bit of a learning curve if you’re used to plain JavaScript.

Yes, it’s worth it.

Typed JavaScript makes refactoring a whole lot easier, and when done right, gives you a lot more confidence in your code. Use the guide in the docs for setup instructions. Make sure to enable strict mode ("strict": true in the compilerOptions).

You can also add type checking in your CI with tsc --noEmit, so you can be confident in your types!

2. Set up a module alias to /src

Set up a single module alias to /src (and a separate one for /assets if needed), so instead of:

import CustomButton from '../../../components/CustomButton';
Enter fullscreen mode Exit fullscreen mode

you can do:

import CustomButton from '@src/components/CustomButton';
Enter fullscreen mode Exit fullscreen mode

I always use a @ or a ~ in front of src to highlight it’s an alias.

I’ve seen implementations where folks set up multiple type aliases – one for @components, one for @screens, one for @util etc, but I’ve found a single top level alias to be the clearest.

There’s a handy guide for setting this up with TypeScript in the React Native docs.

3. Use Inline Styles

You have an option for using the built in inline styles, or Styled Components.

I started off with Styled Components, then switched to inline styles, because there used to be a performance implication, though that’s negligible, so now it’s just a preference.

4. One Style File Per Component

Each component should have their own style file with a styles.ts extension:

FirstComponent.tsx
FirstComponent.styles.ts
SecondComponent.tsx
SecondComponent.styles.tsx
Enter fullscreen mode Exit fullscreen mode

Note, the .styles.ts in the filename is just a convention I use to indicate that the styles belong to the component, the TypeScript compiler will treat these as regular .ts files.

Each style file exports a single style object for the component:

// FirstComponent.styles.ts

import { StyleSheet } from 'react-native';

const styles = StyleSheet.create({
  container: {
    padding: 20,
  },
});

export default styles;
Enter fullscreen mode Exit fullscreen mode

Each component only imports only its own styles:

// FirstComponent.tsx

import styles from './FirstComponent.styles';

...
Enter fullscreen mode Exit fullscreen mode

5. Use Global Styles

Create a globalStyles.ts file at the top level of the /src directory, and import it to the .styles.ts as needed.

Always use constants for:

  • colours
  • fonts
  • font sizes
  • spacing

It may seem tedious at first, but handy in the long term. And if you find you’re ending up creating constant for every single space, it’s something to gently bring up with the Design team, as design guides would generally not want that.

6. Flatten Style Constants

Instead of:

const globalStyles = {
  color: {
    blue: '#235789',
    red: '#C1292E',
    yellow: '#F1D302',
  },
};
Enter fullscreen mode Exit fullscreen mode

Do this:

const globalStyles = {
  colorBlue: '#235789',
  colorRed: '#C1292E',
  colorYellow: '#F1D302',
};
Enter fullscreen mode Exit fullscreen mode

It can be tempting to group these, but I’ve found that keeping them flat can be more handy, e.g. if you wanted to replace all instances of colorRed in your codebase, you could do a find and replace, whereas with colors.red it’d be harder, since the colour could have been destructured.

7. Use Numbers in Style Constants

Instead of:

const globalStyles = {
  fontSize: {
    extraSmall: 8,
    small: 12,
    medium: 16,
    large: 18,
    extraLarge: 24,
  },
};
Enter fullscreen mode Exit fullscreen mode

Do this:

const globalStyles = {
  fontSize8: 8,
  fontSize12: 12,
  fontSize16: 16,
  fontSize18: 18,
  fontSize24: 24,
};
Enter fullscreen mode Exit fullscreen mode

The first option may look nicer when writing it down, but during development, you don’t tend to care about “medium” and “large”, and just care about the number. And it will avoid the awkward naming when the designers inevitably add a font size 14 and you have to start calling your variables things like mediumSmall.

8. One Component Per File

Here’s the template for a new component:

import React from 'react';
import { View, Text } from 'react-native';
import styles from './App.styles';

const App = () => {
  return (
    
      Hello, world!
    
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

Some things to note here:

  • function components over class components: I’d always use function components and manage any state and side-effects using hooks
  • I use constant functions, but both const and function are equally good here. In fact function might be better in the long term
  • default export: I always use a default export, though there is an argument to be made that named exports are better since they’ll be clearer to refactor, and I agree – that might be the next step

9. Separate Components and Screens

Here’s a typical folder structure I end up with:

/assets
  /images
    image.png
    anotherImage.png
  /icons
    icon.svg
    anotherIcon.svg
/src
  /components
    Component1.tsx
    Component1.styles.ts
    Component1.test.ts
    Component2.tsx
    Component2.styles.ts
    Component2.test.ts
  /screens
    Screen.tsx
    Screen.styles.ts
    Modal.tsx
    Modal.styles.ts
  App.tsx
  globalStyles.ts
  types.ts
Enter fullscreen mode Exit fullscreen mode

I always separate components in the /components directory and the screens and modals in the /screens directory. When using react-navigation, there is no structural difference between screens and modals, but I prefer to also differentiate the intent by naming the file SomethingModal.tsx.

Another thing to note is the file names – rather than creating a folder with the file name, and naming each file index.tsx, the filename should reflect the component name. That is mostly for convenience – in most editors, it’ll get tedious to track down which file you’re editing when they’re all called index.tsx

I’ve also seen implementations where all components are imported to a single index.ts file and exported from there. I personally am not a fan of that solution and see it as an unnecessary extra step.

10. Lint Your Code

It’s worth it. Trust me!

  1. Use eslint and prettier – they actually come pre-installed when you initialise a new project
  2. Set up a pre-commit hook – I usually set up a pre-commit hook for linting and pre-push hook for tests. There’s a great guide here.
  3. Check lint, test and TypeScript errors on CI! This is so important – the only way to ensure a consistent code style across the project lifecycle. Setting up CI is one of the first things I do when starting a new project.

Hope this helps! Got any tips of your own that I did’t list here? Let me know in the comments

from Tumblr https://generouspiratequeen.tumblr.com/post/636230780074557442

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s