Home » Blog » Start-up

Tag: Start-up

Building our New React Native App – Tools and Lessons Learned

Building our New React Native App – Tools and Lessons Learned

We started building our first Android-only React Native app about eighteen months ago. Since then, we’ve taken feedback from our users and customers and added features as we went along. A complete redesign was long overdue, both in terms of the UI, UX and the development tools we use. It’s a great feeling to redesign a product and the opportunity doesn’t come around too often. This article details the tools we’ve found useful in the redesign process along with some of the lessons we’ve learned.

Marvel for prototyping

We usually discuss a new feature or improvement at a whiteboard, that gives us a rough idea of what’s needed. Once we have a rough outline, spending a bit of time in Marvel lets me describe the solution I have in my head in more detail and the team once again provides their input. This iterative process lets us quickly create a high-quality feature.

I’ve yet to find a tool better for quick prototyping than Marvel. Their web-based tool lets you quickly create mockups using ready-made icons, shapes and commonly used components. The team behind it frequently adds more features and improvements.

React native debugger

It can be quite difficult to debug a mobile app. React Native Debugger gives you insights into, amongst other features, the state of your app’s React components and Redux state.

Through source maps, it allows you to set breakpoints and step through your running code. The only downside seems to be that settings breakpoints affect performance over time. It can be alleviated by restarting the debugger once in a while.

Formik for forms

Forms without tears. Forms are difficult to implement, regardless whether you’re building an app or anything else, really. This is especially true if you’re trying to make your code maintainable and reusable. Formik manages your form state for you, along with validation and submitting. It does this by adding a layer of sugar coating around the components needed in most forms: error handling, validation, submitting etc.

Formik isn’t a silver bullet, I’m not sure there’ll ever be one for forms, but it’s far better than rolling your own. It’s the best form manager I’ve used so far, it does get a bit tricky if you need to manage your own side-effects, for instance showing your own error state. It can be managed with lower level helper methods that are easy enough to use. The documentation is also comprehensive and easy to follow. Kudos to Jared Palmer for a great library.

UI Components

We used NativeBase in the first version of the app. It provides you with good components and themes. We weren’t using all of its features and the need to wrap our components felt cumbersome. We’ve now switched over to React Native Elements. React Native Elements is a nimble library that provides you with barebones UI components. We’ve been using the beta during development and they just released v1.0.0 a few days ago. So far it’s been exactly what we needed.

Improving components

Speaking of components. We’re always looking to cut down on clutter in our component’s render methods, an effective way of doing so is to get rid of extraneous styling classes, e.g.

({ fontSize: 18, fontWeight: 400 })

And instead, send them in using props. The result is cleaner, reusable components. Our implementation looks something like this.

const TextElement = ({ bold, children, emphasis, h1, h2, h3, ...rest}) => (
  <Text
    style={[
      styles.text,
      bold && styles.bold,
      emphasis && styles.emphasis,
      h1 && styles.h1,
      h2 && styles.h2,
      h3 && styles.h3,
    ]}
    {...rest}
  >
    {children}
  </Text>
)

And can be used like this.

<Text h3 bold>Header</Text>

Tracking

We’re using Google Analytics for tracking what our users do. The library for React Native we’ve been using during development is Google Analytics Bridge. Our goal is to track every screen navigated, button pressed and checkbox ticked. Tracking helps us figure out how our app is used, without having our users explicitly having to provide feedback to us.

In the middle of development, Google decided to sunset the tool so now we have to reevaluate.

“We want to let you know that in October 2019 we will begin to sunset our Google Analytics for mobile apps reporting and the Google Analytics Services SDK.”

React Navigation

We learned while building the first version of our app that navigating between screens isn’t as simple as we thought. We tested multiple libraries and ended up using RNRF. It did what we needed but unfortunately provided some quirks that we didn’t want to have to face again. We’ve now moved to React Navigation. So far it’s looking really good. Version 3 is in its infancy but we’re happy with both documentation, API and performance.

Icons

We ended up base64-encoding all our images and using Native Base’ Icon component in our first version of the app. It’s an easy solution that works straight out of the box but it does make you include many more icons than you need. We wanted to create a solution that would allow us to only add the icons we needed (not all of FontAwesome, for instance).

We use React Native Vector Icons along with IcoMoon and it does exactly what we want. Have a look at this guide that helps you set up your own custom icon set using

Keep proptypes in one place

React has some built-in type checking abilities. These are really handy to make sure you’re sending in the right props for a component. We didn’t spend enough time learning the ins and outs of proptypes in the beginning, we therefore ended up with copies of definitions for each new component. In the redesign, we wanted to make sure we didn’t redefine proptypes every time we created a new component. We made a proptype definition easily accessible by components and views by placing them in src/global/propTypes. Here’s a proptype example of a position of a container on a ship. The file is located in src/global/propTypes/position.js.

import PropTypes from 'prop-types'

export default PropTypes.shape({
  bay: PropTypes.number.isRequired,
  row: PropTypes.number.isRequired,
  tier: PropTypes.number.isRequired,
})

It can then be reused throughout your codebase using.

import propTypes from '../../global/propTypes'
...
YourComponent.propTypes = {
  portCall: propTypes.portCall.isRequired,
}

No longer adding multiple definitions of proptypes.

PropTypes for dynamic keys

This is likely a bit low-level for this article but it took us some time to figure out. We hope it helps you out. If you’re sending a prop with dynamic keys (i.e. you don’t know the keys of an object beforehand), and you only want to make sure that the value is of the correct type e.g. an object with names as properties:

const people = {
  Alice: 1,
  Bob: 2,
}

You can create a proptype for it using

PropTypes.objectOf(PropTypes.number)

This will ensure React only checks that the values are numbers (1 and 2 in the example) but won’t care what the keys are (Alice and Bob). This came in handy for us as we frequently don’t build objects based on one out of several ship structures and therefore don’t know exactly what keys will be used.

Build process

The purpose of our build process is to automatically create a ready-to-deploy product each time we’ve built a new feature or added a new fix to our codebase. For Android, the end result is an Android Package (apk). An apk is the package file format used by Android for distribution and installation of mobile apps.

We’re using CircleCI to help us build our apk. This is how our build pipeline looks:

1. Someone on the team commits code on a separate git branch

2. After a code review by a team member, the branch is merged into master

3. CircleCI kicks off a build, installing a fresh set of dependencies (node_modules)

4. A development apk is built. This is built using the React Native release flag, this allows us to get a feel for how performance on a real device is. It reads and submits data from our development database so we can try it out as much as we want

5. CircleCI waits for our input. If we need it, we kick off the build of a production apk (an apk that submits and reads data from our production database)

6. Apk’s are pushed to an AWS s3 bucket, ready to be deployed

Final thoughts

One of the bigger upsides with a framework maturing is that the accompanying tooling follows suit. The wheel has been reinvented many times over by now and it helps us greatly as we build our product, letting us move at a pace we never could have achieved without them.

If you find a tool, react native component or library that you find particularly useful, we suggest you try to return the favour by submitting bug reports or even providing a fix for one you’ve found. Make sure you have a quick chat with the tool creator to make sure they’re aware of the problem and is willing to merge your code changes once you submit a fix.

That’s it for now. We hope reading about the tools we found helpful will aid in your development.

Do you know of any way for us to improve or of better tools? Please reach out to us on crew@intelligentcargosystems.com, we’d love to hear what you have to say.

Intelligent Cargo Systems is a seed stage shipping technology startup. Our groundbreaking platform accurately forecasts cargo completion time far in advance of current methods. This helps container ship operators anticipate delays, reduce turnaround time in port, save money on fuel and reduce their environmental impact. Available in every port worldwide, it offers unrivalled real-time port visibility and performance reporting.

Dennis Sandmark, CTO and Co-founder