TIL #1 - Managing Typography in React Native TypeScript

Published
Aug 8, 2020
Tags
code
typescript
react-native
🗓 August 8th, 2020
 
In this post, I wanted to share what I’ve learned while tinkering with React Native TypeScript. Several things that we’ll be doing:
  1. Create React Native TypeScript project
  1. Adding a custom font to React Native application
  1. Make use of TypeScript’s enum feature to create a Text component

Create a React Native TypeScript project

To initiate this project, I used npx. The main reason I used npx is I can execute any package directly from the npm's registry without installing the package. The command that I use is
npx react-native init TILRNTypography --template react-native-template-typescript
The --template react-native-template-typescript flag will use React Native Community’s TypeScript template .
When the app initiated, we’ll have project folder with this structure:
| __tests__
| android
| ios
|- app.json
|- App.tsx
|- babel.config.js
|- index.js
|- metro.config.js
|- package.json
|- ts.config.js
|- yarn.lock

Adding Font to React Native app

Download and save the font

In this project, I use Montserrat font. This font can be downloaded from Google Font. Before saving the font to this project, I created a new directory: src/assets/fonts. Then I save the font there. As a note, I only stored the variants that I’ll be using which are Regular, SemiBold, and Bold. The new directory structure should be looked like this
| __tests__
| android
| ios
| src
| | assets
|   | fonts
|     |- Montserrat-Bold.ttf
|     |- Montserrat-Regular.ttf
|     |- Montserrat-SemiBold.ttf
|- app.json
|- App.tsx
|- babel.config.js
|- index.js
|- metro.config.js
|- package.json
|- ts.config.js
|- yarn.lock
 

Link the font

Then to make sure that the font can be used in our app, we have to link the font as the project assets. There are 2 ways to do this depending on the React Native version.

Version < 0.60

At these lines in the package.json
{
	...,
  "rnpm": {
    "assets": [
      "./src/assets/fonts/"
    ]
  }
}

Version >=0.60

Create a new file named react-native.config.js in the project’s root directory. Then fill the file with these lines
module.exports = {
  project: {
    ios: {},
    android: {}
  },
  assets: ["./src/assets/fonts/"]
}

Run the link

Link the asset using this command
npx react-native link
 
This command will link the fonts that we stored in ./src/assets/fonts to the Info.plist in the ios/{project_name} for iOS and create a new directory in ./android/app/src/main/assets/fonts for Android.
At this phase, the fonts are ready to use using fontFamily attribute. For instance
<Text style={{ fontFamily: 'Montserrat-Regular' }}>Contoh</Text>

Make use of TypeScript’s enum feature to create Text component

We will create a Text component that will accept the text’s type as a prop. In this case, I define 3 types of Text: H1, H2, and Paragraph. There are a lot of ways to do this, but in this post, I’ll use enum.

Text component

The first step is to create a file called Component__Text.tsx in the new directory called ./src/components.
| __tests__
| android
| ios
| src
| | assets
| | | fonts
| |   |- Montserrat-Bold.ttf
| |   |- Montserrat-Regular.ttf
| |   |- Montserrat-SemiBold.ttf
| | components
| | |- Component__Text.tsx
|- app.json
|- App.tsx
|- babel.config.js
|- index.js
|- metro.config.js
|- package.json
|- ts.config.js
|- yarn.lock
First, import the needed modules in the Component__Text.tsx
// Component__Text.tsx
import React from 'react';
import {Text, StyleSheet} from 'react-native';
Then, define the text’s types in enum, let’s called it TextType. I export the TextType to make sure it’s available to another module that will use this component.
// Component__Text.tsx
// ...
export enum TextType {
  H1,
  H2,
  Paragraph,
}
After that, we create a style for each type of text that already defined
// Component__Text.tsx
// ...
const STYLES = StyleSheet.create({
  H1: {
    fontSize: 30,
    fontFamily: 'Montserrat-Bold',
  },
  H2: {
    fontSize: 20,
    fontFamily: 'Montserrat-Semibold',
  },
  Paragraph: {
    fontSize: 14,
    fontFamily: 'Montserrat-Regular',
  },
});
Then, create the Text component with its props' type. The component will use the type prop to create its style.
// Component__Text.tsx
// ...
type TComponent__TextProps = {
  type?: TextType;
  children: string;
};

const Component__Text = (props: TComponent__TextProps) => {
	const makeStyle = () => {
    switch (props.type) {
      case TextType.H1:
        return STYLES.H1;

      case TextType.H2:
        return STYLES.H2;

      case TextType.Paragraph:
      default:
        return STYLES.Paragrah;
    }
  };
  return <Text style={makeStyle()}>{props.children}</Text>;
};

export default Component__Text;
The complete code for Text component should looks like this
// Component__Text.tsx
import React from 'react';
import {Text, StyleSheet} from 'react-native';

export enum TextType {
  H1,
  H2,
  Paragraph,
}

type TComponent__TextProps = {
  type?: TextType;
  children: string;
};

const Component__Text = (props: TComponent__TextProps) => {
	const makeStyle = () => {
    switch (props.type) {
      case TextType.H1:
        return STYLES.H1;

      case TextType.H2:
        return STYLES.H2;

      case TextType.Paragraph:
      default:
        return STYLES.Paragrah;
    }
  };
  return <Text style={makeStyle()}>{props.children}</Text>;
};

export default Component__Text;
 

Using the Text component

Import the Text component that we’ve created to the App.tsx
// App.tsx
import React from 'react';
import {SafeAreaView, StyleSheet} from 'react-native';

// Import the Text component
import Text, {TextType} from './src/components/Component__Text';
Then, use the component with its various styles
// App.tsx
const STYLES = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});
const App = () => {
  return (
    <>
      <SafeAreaView style={STYLES.container}>
        <Text type={TextType.H1}>Heading</Text>
        <Text type={TextType.H2}>Heading 2</Text>
        <Text type={TextType.Paragraph}>Ini contoh body</Text>
      </SafeAreaView>
    </>
  );
};

export default App;
The complete code for App.tsx should looks like this
// App.tsx
import React from 'react';
import {SafeAreaView, StyleSheet} from 'react-native';

// Import the Text component
import Text, {TextType} from './src/components/Component__Text';

const STYLES = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});
const App = () => {
  return (
    <>
      <SafeAreaView style={STYLES.container}>
        <Text type={TextType.H1}>Heading</Text>
        <Text type={TextType.H2}>Heading 2</Text>
        <Text type={TextType.Paragraph}>Ini contoh body</Text>
      </SafeAreaView>
    </>
  );
};

export default App;
If everything is working correctly, we should see this in the app
notion image

Phew, I think that’s all. Thank you for reading through this post!
Cheers and happy coding! ✌️💻