Configuring a new React Native App

I was brand new to React just a few months ago. Then I was given the opportunity to start a new React Native project at work with our Lead Senior Developer. Being the obsessive information gatherer I am, I was so excited. I read a lot of blogs, and watched a lot video tutorials.

At the beginning of a project, I find file organization and general configuration to be very important. Between the other developer and myself, we came up with a file structure I think works well to organize configurations, components, navigation, constants and reused styles. I can’t start this post without first referencing the blog I found most helpful in organizing a React Native app.

The setup I go through is similar, and I offer some insight into what the configuration code looks like inside the files as well.

For these examples, I created an app to list yoga poses in sanskrit and english that uses React Native of course, React Navigation and React Native Elements.

If you start your project using react-native init then you’ll open up your text editor to a file system that looks like this:

At the root of the project, I add a /src directory which houses all the code I will write. I also like to add a resources directory to put my custom font files since those will be accessed by Android and iOS in different ways.

Here is what it looks like inside those directories.

You can see I have all my font files in /resources/fonts and in /src I have a number of files. Let’s dive into them a little more, in order of how I go through configuring the project.

/src/assets

This is what you would expect; I put an /images directory in here and if need be, I separate the images out even further into directories like /logos, /icons, etc.

/src/config

After I add resources (fonts) and assets (images), I start on config files.

/src/config/colors.js

The first file I usually create is colors.js because it’s super straight forward. For my yoga app, I have my colors configured as follows.

/**
* @providesModule Colors
*/
const colors = {
black: '#000000',
night: '#333333',
charcoal: '#474747',
gray: '#7D7D7D',
lightishgray: '#9D9D9D',
lightgray: '#D6D6D6',
smoke: '#EEEEEE',
white: '#FFFFFF',
ypsDark: '#47546E',
yps: '#637599',
ypsLight: '#7B92BF',
cosmic: '#963D32'
};
export default colors;

Note the top comment. This allows me to import Colors anywhere in the app without worrying about the path to the file. I use this in all my configuration and component files.

Now, throughout the app, all I need to do in order to use any of these colors, is import it using import colors from 'Colors'; and then reference any color where needed using colors.white or whatever the color name is.

/src/config/fonts.js

Great! Then, I can set up fonts after adding them to iOS and Android. Side note: adding fonts to a RN project can be a little bit of a hurdle the first time around. Here are some resources I use:

How to add and remove custom fonts in React Native by Daniel Skripnik

Adding Custom Fonts to A React Native Application for IOS by Nader Dabit

OK, back to fonts.js. Again, this is another super easy configuration file.

/**
* @providesModule Fonts
*/
const fonts = {
openSansLight:'OpenSans-Light',
openSansRegular:'OpenSans-Regular',
openSansSemibold:'OpenSans-SemiBold',
openSansBold:'OpenSans-Bold'
};
export default fonts;

/src/config/typography.js

Since I have my fonts set up, I can go to filling in typography.js. In the styleguide for this app, I have large, medium and small text. And for each size, I have a regular and semibold option.

/**
* @providesModule TextStyles
*/
import { StyleSheet } from 'react-native';
import fonts from 'Fonts';
const largeText = 16;
const mediumText = 14;
const smallText = 12;
const regularText = fonts.openSansRegular;
const semiboldText = fonts.openSansSemibold;
const textStyles = StyleSheet.create({
largeText: {
fontFamily: regularText,
fontSize: largeText
},
largeTextSemibold: {
fontFamily: semiboldText,
fontSize: largeText
},
mediumText: {
fontFamily: regularText,
fontSize: mediumText
},
mediumTextSemibold: {
fontFamily: semiboldText,
fontSize: mediumText
},
smallText: {
fontFamily: regularText,
fontSize: smallText
},
smallTextSemibold: {
fontFamily: semiboldText,
fontSize: smallText
}
});
export default textStyles;

Terrific; text styles added. Since I will use text all over the app, to keep things DRY, I like configuring these repeatable styles here, and then also create a component for each text type (small, medium & large in this case). If anything were to change (say small text point size goes to 11 instead), I can change it in this one place, typography.js.

/src/config/buttons.js

Next up, we’ll look at the buttons.js file. Again, buttons are used a number of times typically, so I like to start with a style configuration file, and then I also create a custom button component to be reused throughout the app.

/**
* @providesModule ButtonStyles
*/
import colors from 'Colors';
import constants from 'Constants';
import { StyleSheet } from 'react-native';
const buttonStyles = StyleSheet.create({
buttonPrimary: {
height: 42,
borderRadius: 3
},
buttonOutline: {
height: 42,
borderRadius: 3,
borderWidth: 2
},
buttonOutlineDark: {
...buttonOutline,
borderColor: colors.white
},
buttonOutlineWhite: {
...buttonOutline,
borderColor: colors.white
},
buttonFull: {
width: '100%',
marginLeft: 0,
marginRight: 0
}
});
export default buttonStyles;

/src/config/icon-font-config.json & /src/config/icon-font.js

Another biggie for most apps I work on is a custom icon font. If you’re using React Native Elements, then React Native Vector Icons is already included as a dependent. If not, you would want to add it in order to add a custom icon font. With this, you get a ton of existing icons from Font Awesome, Ionicons, etc., and the ability to add your own custom font (documentation to do so here).

When I follow the custom font instructions using Fontello, I end up with the icon-font-config.json file which has a bunch of json with the svg paths and whatnot, and the icon-font.js file which looks like this.

/**
* @providesModule MyIcon
*/
import { createIconSetFromFontello } from 'react-native-vector-icons';
import fontelloConfig from './icon-font-config.json';
const Icon = createIconSetFromFontello(fontelloConfig);
export default Icon;

/src/config/inputs.js

I’m on my way to being able to actually create components! Next up I’d go after the inputs.js file, much like buttons and typography so I can reuse the styles and create a custom input component if I want to.

/src/config/images.js

And of course, I already have our image assets available in the/assets directory. But I need to configure them in order to easily use them throughout the app, and also update them if I, or my designer, decides to change a logo or something. Simple enough!

/**
* @providesModule Images
*/
const images = {
logo1x: require('../assets/images/yps-logo.png'),
logo2x: require('../assets/images/yps-hero.png'),
logo3x: require('../assets/images/yps-goodbye.png')
};
export default images;

/src/config/spacing.js

The last three files in the /config directory are super useful to me. These are spacing.js, constants.js and functions.js. Spacing throughout an app is also important to be consistent. Basically anything related to spacing that will be used over and over, I like to put in here. That way I can update it in one spot if need be. Here are some of the regulars I use.

/**
* @providesModule Spacing
*/
import { StyleSheet, Platform } from 'react-native';
import constants from 'Constants';
import colors from 'Colors';
let defaultSpacer = constants.defaultSpacer;
let positions = ['Top', 'Right', 'Left', 'Bottom'];
const spacing = StyleSheet.create({
container: {
display: 'flex',
alignItems: 'center',
flexDirection: 'column',
padding: constants.viewPadding,
backgroundColor: colors.white,
justifyContent: 'space-between',
height: constants.viewHeight
},
scrollContainer: {
backgroundColor: colors.white,
flex: 0,
minHeight: constants.viewHeight
},
viewPadding: {
padding: constants.viewPadding
},
viewPaddingHorizontal: {
paddingLeft: constants.viewPadding,
paddingRight: constants.viewPadding
},
viewPaddingVertical: {
paddingTop: constants.viewPadding,
paddingBottom: constants.viewPadding
}
});
positions.forEach((position) => {
var paddingString = ('padding' + position)
var marginString = ('margin' + position)
spacing['addPadding' + position] = {
[paddingString]: defaultSpacer
}
spacing['addMargin' + position] = {
[marginString]: defaultSpacer
}
});
export default spacing;

The main items are containers, viewPadding, and padding or margin. I like to have a default which is expected to be used whenever spacing is needed, but of course know there will be instances where padding or margin will be smaller or larger, and in those cases, I add the styles individually.

/src/config/constants.js

You can see I use constants above, which is where I set the viewPadding and some other reusable items like the following. Whenever I find myself repeating something over and over (like getting the screen height), I go ahead and add it here so I can reference it easily.

/**
* @providesModule Constants
*/
import { Dimensions, Platform } from 'react-native';
import colors from 'Colors';
let headerHeight = Platform.OS === 'ios' ? 66 : 46;
let footerHeight = 55;
const constants = {
headerHeight: headerHeight,
footerHeight: footerHeight,
viewHeight: Dimensions.get('window').height - headerHeight,
viewPadding: 15,
defaultSpacer: 10,
screenHeight: Dimensions.get('window').height,
screenWidth: Dimensions.get('window').width,
divider: {backgroundColor: colors.smoke},
baseImageStyle: {flex: 1, width: undefined, height: undefined}
};
export default constants;

/src/config/functions.js

And last is functions.js, which is great to store those minor things you just have to do over and over. An example would be formatting a date possibly. This is not to be used for anything related to API requests, but purely for simple functions, mainly used for presentation purposes.

Wow… lots of configuration! What about components?

Now I have most of the tools needed to sprint through creating our presentational components, and then container components. Haven’t read about presentational vs container components? This is a great spot to read about them. In an effort to not go into deep explanation, basically presentational components are going to be your UI Elements and container components will bring those presentational ones together and actually pass data through to them.

/src/components

Finally creating some React Native components! You can see I separate them into container vs presentational below.

/src/components/presentational

Under presentational I do have a separate typography directory, because as I mentioned earlier, I like to create a component for each text style. Just to give you an idea, here is what my Large Text component looks like.

/**
* @providesModule LargeText
*/
import React, { Component } from 'react';
import {
StyleSheet,
Text
} from 'react-native';
import textStyles from 'TextStyles';
import colors from 'Colors';
class LargeText extends React.Component {
render() {
return (
<Text
{...this.props}
style={[
this.props.bold == true ? textStyles.largeTextSemibold : textStyles.largeText,
{color: this.props.color},
this.props.style
]}>
{this.props.children}
</Text>
)
}
};
LargeText.defaultProps = {
color: colors.night,
bold: false
};
export default LargeText;

Now, I can use large text styles anywhere throughout the app, by importing this component and then using it in my markup like this.

...other imports 
import LargeText from 'LargeText';
...defining class
<View>
<LargeText bold={true}>Yoga Pronounce Sanskrit</LargeText>
</View>
...export

Other presentational components can be things like a button, a dropdown, list header, tabs, input, top navigation bar. There will be a variety of elements in here based on your app design of course. I think these are super fun. :) When I’m building out the presentational elements, I like to set myself up a styleguide page where I throw the components’ markup with static text, images, etc. This way I, along with any other developers working on the project, can easily see how the component is implemented and then use as needed.

/src/components/container

In my /container directory, I don’t have a whole lot here, but this is where I place those components that host a number of other UI components. There isn’t a hard and fast rule about what is considered container vs presentational, so I just have to kind of judge what works for my app.

/src/screens

You can see at the bottom of that file structure I have a /screens directory. Now, technically these screens are components. And really, they’re container components. I go back and forth where these should live in my file structure, but for right now, in this moment, I like them to be in their own little home. This way I can easily find the starting point to any given component.

/src/models

This is something the senior developer I work with set up initially, and I like to use. It may or may not be included depending on what is being used to handle API requests and app state. I like to use it to host files where API request are made. That way I can import them and fetch, or update anything I need to from any component and not have to repeat request functions.

/src/navigation

And last but not least, this is pretty self explanatory — navigation configuration will go in here.

That’s what I got!

So there it is! I’ve been on a few projects with React Native now, and my preference in file structure and configuration set up is close to where it started, but has evolved a little to what I have above. I’m sure this will be ever evolving, and of course I am always always open to hearing any suggestions!

❤ Kelley