A Friendly Guide to Clean Code in React Native and Expo for Dummies

Hocky Yudhiono
10 min readFeb 25, 2022

This year, I’m taking a Software Engineering Project course. My team (consisting of 7 people) was assigned to a task of a cryptocurrency mobile application! I’m so excited to spend the rest of the semester doing this project. As I have no knowledge of mobile app developing and cryptocurrency, at all beforehand.

We will be using React Native: Expo as our main framework. It’s really similar to React.js, but I only had like 2 weeks worth of experience using React.js. So I’m a bit dumbfounded with this. I won’t let you be as empty as me when I first started doing this, so I will help you going through this!

If you are really familiar to React and React Native, please do roast this post and correct all the statements I made 🧙‍♂️!

The Creation of Adam Gif
The Creation of Adam But It’s Cool

To be honest, I didn’t really wanna write just about clean code, but yes we will learn this “Clean code” from the Scratch. Like literally scratch 🍡.

Things You Should Know

How React Native Works

React Native is JavaScript code running on mobile devices for real. It uses the JavaScriptCore to run the code in a separated thread, in parallel with the Main Thread(Objective-C, Java, etc) and the Shadow Queue, the layout thread.

State, Lifecycle, Magic, Confusion

This, is where people would stuck with React, and giving up with their ok-it-works-even-though-it’s-gross code in React. You must understand the state and lifecycle in react (it’s the same for React.js and React Native)

  • Mounting, this will run only once for the first time when you’re trying to render a page
  • Updating, this will run multiple times and cause the components to “re-render”
  • Unmounting, when you hide a component or move into another page, this will happen.

Every application we will develop will be made up of components, in newer react, components are functional. Each components will take props as a parameter. Props are something that you want to initialize your components with or anything a component must know to keep the program running.

By default, when your component’s state or props change, your component will re-render.

State is something that is inside the component, more like a local variable, props must be updated outside the component.

A component cannot update its own props unless they are arrays or objects (having a component update its own props even if possible is an anti-pattern), but can update its state and the props of its children.

A React component should use props to store information that can be changed, but can only be changed by a different component.

A React component should use state to store information that the component itself can change.

With this, hopefully you understand the hardest part of React, and not use it in a wrong way, using a counterintuitive design pattern or something weird. In a way, both of them are immutable, changing their value should assign them to a new pointer instead of like appending or adding something into the object or array.

setTheArray(prevArray => [...prevArray, newValue])
setTheObject(prevState => ({ ...prevState, currentOrNewKey: newValue}));

Just act like it’s immutable. Even though the object is mutable so that this will trigger the re-render of a react component.

Styling

React native doesn’t use HTML and CSS, but it does use styling commands and configurations that is built into react native. It was written in JavaScript. But chill, it’s based on CSS syntax (not really complete and exact though, just the subset), it won’t take you much time to learn and spend your worthy time like doing TDD — (Dear lecturer and assistant team, it’s a Joke please don’t cancel me).

React Native enforce us to use Flexbox layouts by default. So we don’t need to use float and display to build our layout structure.

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

const LotsOfStyles = () => {
return (
<View style={styles.container}>
<Text style={styles.red}>just red</Text>
<Text style={styles.bigBlue}>just bigBlue</Text>
<Text style={[styles.bigBlue, styles.red]}>bigBlue, then red</Text>
<Text style={[styles.red, styles.bigBlue]}>red, then bigBlue</Text>
</View>
);
};

const styles = StyleSheet.create({
container: {
marginTop: 50,
},
bigBlue: {
color: 'blue',
fontWeight: 'bold',
fontSize: 30,
},
red: {
color: 'red',
},
});

export default LotsOfStyles;

In React Native, <View/> is somewhat equivalent to a <div/> in HTML, for a full list I somehow recapped all this:

  • <div>: <View>
  • <span> or <p>: <Text>
  • any type of inputs: <Input>
  • <a> or <button>: <Button>
  • <img>: <Image>

Clean Code

Too many issues happening when we code — In whatever programming language you’re writing right now. But the almost same practice is we must do clean code. In this section I will write some most common issues in React Native code.

Styling and Components

Inline styling is not really a good practice, we should use separated styling module instead for a better result and readable code, unrelated code should be separated into components, and each component can be separated into different files. Then, duplicated codes, should be separated into parameterized components.

Expect Multi-Language Feature

Genshin Impact in Bahasa Indonesia

Almost all games have this feature, so.. Bunch of ifs and elses must not work in this case, right? How to separate the translation objects I wonder.

// en/navigate.js
export default {
home: 'Home!',
settings: 'Settings'
};


// id/navigate.js
export default {
home: 'Beranda',
settings: 'Pengaturan'
};

Some string literals are best to not be written and coded into the render return directly. In a small scale, yes. But when any literal is used in more than one places, it’s better to gather it in one place. For now, let’s just ignore the translation part. Even in a monolingual app, separating the literals can help us to debug typo in just one file! How convenient!

Adapting it Into My Software Engineering Project

In my software engineering project, clean code is one of the biggest concern to work with a team 7 people. I can’t do anything if I don’t understand your code. So, I adapt several things.

Setting Up Linter, Use Effective Typescript

Lint, or a linter, is a static code analysis tool used to flag programming errors, bugs, stylistic errors and suspicious constructs.

In a project, linter is as important as your lunch, breakfast, and dinner. It can basically check whether you’re doing is “Syntax”-ly normal.

Setting a static typed variable in Typescript is really hard, as we can’t really find the class name or the variable type properly if we don’t understand the code! But typescript will help us to find errors when assigning something to a function, the linter can also automate the checking statically and live while we’re typing.

The linter can also help tidy up the imports.

The Library Stylesheet Pattern

When we’re using a css props library like Tailwind or NativeBase, we don’t really create StyleSheet.

Instead, the library encourage us to create components instead to reduce the clunked styles in each component. WIth this, it will be compact and the styling should be inline and easy to debug.

Foldering

Foldering is also part of clean code. You don’t want your code to be in one place because it will be hard for you the next time you want to search it.

Setting Up Git Pre-commit Hooks

There is an app called husky, in which you set up to encourage the developer to pass the linter before commiting. This will encourage and force clean code throughout your codes.

Testing in Jest

This is a good article to catch: https://markus.oberlehner.net/blog/naming-your-unit-tests-it-should-vs-given-when-then/

Testing in Jest is pretty cool, test and it is like a module of test (both of them are the same, it’s basically just an alias) and describe is like the test class. We can do before each in a scope of one “describe”. The test encourage us to do good naming of test! So cool

describe('Given the balance is 1.000 €', () => {
describe('When making a deposit of 100 €', () => {
test('Then I expect the balance to be 1.100 €', () => {
// ...
expect(theBalance).toBe(1100);
});
it('Shoukd be error when I have no money', () => {
// ...
});
});
});

Adapting Your Classic Textbook Clean Code Principle in React Native

There are some old classic textbook principle that still works nowadays, those are:

You Aren’t Gonna Need It (YAGNI) and Keep it Simple Suckass!

Always implement things when you actually need them, never when you just foresee that you need them.

In a react native working environment, you sometimes will meet modules you don’t need, or utility code that you code, not knowing there are already built in modules to do it. Let me show you one of the one thing I improve in my code.

useEffect(() => {
let isSame = true;
const newClickableMnemonics = Array(mnemonics.length).fill(true);
if (mnemonics.length != mnemonicsBox.length) isSame = false;
else {
for (let i = 0; i < mnemonics.length; i++) {
if (mnemonics[i] != mnemonicsBox[i]) {
isSame = false;
break;
}
}
}
for (let j = 0; j < randomedMnemonics.length; j++) {
for (let i = 0; i < mnemonicsBox.length; i++) {
if (randomedMnemonics[j] == mnemonicsBox[i]) {
newClickableMnemonics[j] = false;
break;
}
}
}
setConfirmable(isSame);
setClickableMnemonics(newClickableMnemonics);
}, [mnemonicsBox]);

This code, can be shortened to:

import { isEqual } from "lodash";
isDisabled={!isEqual(mnemonicsBox, mnemonics)}

Yes, why code everything you don’t need? Why implement something that already exist before with better implementation? We should keep everything as simple as possible, and if you stuck you should ask a friend to help you for a better idea of implementation 😊.

In YAGNI, we should spend less time on features that we aren’t really gonna use etiher way. For example when I do code for the confirmation screen, I was thinking of adding a drag sort.

But I was thinking, is this necessary? Will the time hold the release of the feature of this sprint? And the answer is Yes! We should just stick to the PBI for this one 💛, and you shouldn’t add something before asking other member of the development team about this.

So when should we consider adding this feature?

  • If time allows
  • If sprint has extra time
  • If product owner accepts the feature suggestion

And yes. Don’t be a feature creep! Avoid extra features! and if you wanna add, you should ask for permission on the team first.

Don’t Repeat Yourself

React native is a component oriented programming language, everything is a component. You don’t want to repeat yourself making the same component over and over again. This is why components are encouraged. The rule of thumb is:

  • If there are more than one component using the same implementation, you should make a new component out of it so you can reuse it. This will avoid: recode, bug fixing hassle on multiple spots.
  • If there are a list that should be made several time, you should utilize looping
  • If there are constants you use more than twice, you also should use a named constant on top of the components, not just to increase readability, but this will also increase your cleanliness of your code.

SOLID

This one principle relates strongly with react native:

  • Single Responsibility Principle, each components should hold one business idea, if there are more than one it’s encouraged to split it into some other more modular components.
  • Open-Closed Principle, extending a component rather than changing it when a component is nested inside others is a best practice in a language.
  • Liskov Substitution Principle: Those components shall work harmoniously, the tests passed for the parent components shall pass for the childrens too.
  • Interface Segregation Principle: Well we don’t really do interfaces in react native but yes. Optional types and parameter is good in here. You should specify what property and parameters shall be provided into one component, and client should never be forced to put in data they don’t need.
  • Dependency Inversion Principle: This closely relates to hollywood principle, in react native this shall be interpreted as the parent class will hold the main controlling object that can be passed into the kids.

That’s It!

Now I wish this blog is worthy enough to gain full points for the blog post grading HAHAHHAHA. I’m so tired.

References:

--

--

Hocky Yudhiono

Fullstack Developer 💻, Competitive Programmer 🐭, Blogger 📝, Eager Learner 💤 | https://hocky.id/