Sharing Code between React.js and React Native

My first HTML 5 game Basic Pairs is one code base for both the web and android version.
What’s good, is that I managed to figure out a way to share most of the code. This is what I learned sharing code between React.js and React Native.

Project Structure

I’ve been using [Create-React-App]. I wanted to combine a CRA folder structure, with what you get from react-native init.

Step 1 – Copy Public and Src

Create-React-App makes this simple as it relies mostly on react-scripts. The scripts rely on the source code being in a folder called src and the html file living in public.

So I copied those two folders from the CRA folder into the React Native folder. Then moved onto updating package.json.

Step 2 – Package.json

Nothing special here either. I just compared the two package.json files and pretty much merged them. Unfortunately, they both have a “start” task. So I prefixed all the CRA tasks with “web-” (lined 8-11 below).

{
  "name": "BasicPairs",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start",
    "test": "jest",
    "web-start": "react-scripts start",
    "web-build": "react-scripts build",
    "web-test": "react-scripts test --env=jsdom",
    "web-eject": "react-scripts eject"
  },
  "dependencies": {
    "react": "15.4.1",
    "react-dom": "15.4.1",
    "react-native": "0.38.0",
    "react-native-button": "^1.7.1",
  },
  "jest": {
    "preset": "react-native"
  },
  "devDependencies": {
    "flow-bin": "^0.33.0",
    "babel-jest": "17.0.2",
    "babel-preset-react-native": "1.9.0",
    "jest": "17.0.3",
    "react-scripts": "0.7.0",
    "react-test-renderer": "15.4.1"
  }
}

The CRA site now runs with npm run web-start. The React Native app continues to run with react-native run-android.

So far, so good, but how to share code?

Sharing Code

In an ideal world, you would be able to share 100% of the code. As far as I know, that isn’t possible, but we can share a lot of it. Although React Native is like React.js, the rendering code is different. Instead of “div” you have “View”, text also has to be wrapped in “Text” tags and the list goes on. The “business logic” is just JavaScript though and that’s what we can share.

I don’t quite understand how this works. But as far as I can tell, it’s webpack magic. When webpack links the files, it takes notice of the filenames. The “trick”, is that you can have a React component defined in one file. Yet have the render method in a target platform specific file.

Webpack Linking Correct Files

Webpack Linking Correct Files

Let’s say you want to create a component called “MyComponent”. Webpack is aware of the target platform. Webpack uses this when trying to resolve `import MyComponent from ‘./MyComponent’:

  • When the target is android, it will search first for “MyComponent.Android.js”
  • If it can’t find that file and the target is android, it will search for “MyComponent.Native.js”
  • If it can’t find that file and the target is android or the target is web, it will search for “MyComponent.js”

What’s more, you can use this trick to split out just the render method. So let’s use that to our advantage to create a simple component.

Split Out the Render Method

To try it out, create a folder in src called MyComponent. Then create a “Render.js” file containing the following. This will be used in the CRA build.

import React from 'react';

export default function render() {
    return (
        <div>
            Hello World!
        </div >
    );
}

Then create a React Native file called “Render.native.js”. (this would be for Android and IOS):

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

function render() {

    var styles = StyleSheet.create({
/…
    })

    return (
        <View style={styles.whatever}>
            <Text>
                Hello World
            </Text>
        </View>
    );
}

module.exports = render;

Finally, lets define the component. Create a file called “Component.js”:

import { Component } from 'react';
import Render from './Render';

class MyComponent extends Component {

    // Shared Code Here

    render() {
        return Render.bind(this)();
    }
}

export default MyComponent;

Note how Render is imported and then called in the render() method.

Any code defined here is available to both the “Render.js” and “Render.native.js” files.

That means you can define a single “onHandleClick” method and pass it down via props.

Warning

I’ve only been using this technique for a couple of weeks, so there may be problems with it.

My first attempt copied the folder structure from the React Native output into the CRA output. All was well until I tried a react-native upgrade. I’m not sure, but it appears that the folder name is used during upgrade. Long story short, it all stopped working and I only fixed it by starting again using this approach!

I might end up moving the src folder to a different package and using npm link to get it into 2 code bases. The code will be shared, but I’ll have two projects to maintain.

Just make sure you have everything under source control so you can rollback.

Conclusion

I’ve used this technique in Basic Pairs and have shared the vast majority of the code between the CRA and React Native app.

I added a button to the React Native app and plumbed in some onPress logic. Using this technique saved a lot of time as it worked first time for the CRA onClick event.

I’m always looking to improve. So please let me know in the comments below if I’ve made a mistake or missed something. Failing that, contact me on twitter.

Income Report for November 2016

I’m making my income reports, including traffic numbers, public. That way, anyone thinking of starting something similar can see real world numbers. There are a lot of other sites sharing their income, so why does the world need another one?

I’m sharing the figures from month 1, which isn’t that common. Also, I can’t see many income reports from mobile app developers. So I’m hoping that this is something unique.

My hope is that these reports will inspire someone else to try something themselves. Please let me know if you think I can improve them. I’m always looking for ways to improve.

Current Status

I broke Google Analytics for the first 10 days of the month. So the graphs below look a bit rubbish and I don’t really know where I stand. It’s not the end of the world, but slightly frustrating as my analysis is part guess work.

The main event this month was deciding to focus 50% of my time on making HTML 5 games. So far I have built a Basic Pairs game and plan to progress to more complex games as time goes on.

I have also decided to stop tweeting and pinning so much stuff. It simply isn’t driving traffic to the site. I’m sure there’s an argument that I’m doing it wrong, the content on this site isn’t good enough or something else. That’s fine, I’m all about ROI at the moment. Or more accurately, learning more stuff so I can get an income source.

Hours this month

As always, I track the hours I’m spending on this project. It helps me track “return on investment” and highlights how much effort is required for something like this.

Topic Hours
Income Report October 2016 2
New Plan Games Post 1
Pairs Game 25
componentWillReceiveUpdate Post 2
React.js Games – Basic Pairs Post 3
React TV Tracker Part 2 8
Updated Meeting Cost 2
Chrome Extension 3

Total Hours this month – 46

A nice lot of hours this month. I’m hoping this will increase in December and January as I’m no longer in full-time employment and plan to concentrate on this site a little more.

Traffic for MM YY

Audience Overview - November 2016

Audience Overview – November 2016

You can see the flat line at the start of the month where I broke analytics. I’m also lacking the big peak in the middle. But, ignoring the spike, for almost all days, the blue line is above the orange one. Progress.

Audience Stats - November 2016

Audience Stats – November 2016

Most of the stats are broke as I’m missing a 3rd of the data. Bounce rate is lower though, so lets hope that trend continues.

Page Views Top 10 - November 2016

Page Views Top 10 – November 2016

HTML 5 games was clearly a good thing. They’re new pages this month and they’re already in the top slots. I did promote them a little though, so that definitely helps. Perhaps I should spend more time “marketing”.

Acquisition Overview - November 2016

Acquisition Overview – November 2016

And this is why I’m putting a stop to the time I’m spending on twitter and pinterest.

Monthly Income

Description Value
AdSense £0.27
Chitika Ads £0.02
Chitika Referal £0
TsoHost Referal £0
Amazon Associates £0

Total Income £0.29

Monthly Expenses

Description Value
Site Hosting £1.25 (£14.99 a year)

Total Expenses £1.25

Profit over time

Total Profit £1.25 – £0.29 = £-0.96

Income Over Time - November 2016

Income Over Time – November 2016

Another record month! Shame it’s only a few pennies above last month. I’m also expecting this to take a big drop when I try to deploy my first app. $25 developer licence is huge in comparison!

Analysis

The daily average traffic to this site is increasing. I’ve had about the same number of page views as last month but haven’t had a single post smashing all records. That’s got to be a good thing as I can’t expect to produce something that resonates with people every month.

Income has also increased again, but only just. I have a long way to go to hit the first year plan of £10/month profit.

Lessons learned this month

Don’t tweak the live site

I broke Google Analytics as I was playing on the live site. I need to setup a staging or development site somewhere so this can’t happen again.

Having a Focus is Great

Up to now, I’ve been playing with whatever I wanted. It was fun, but the output wasn’t great. Now that I have a focus on HTML 5 games, I can build a backlog of work and focus. My productivity has increased and I feel happier about things.

I need to apply this to the other 50% of my time ASAP!

Progress this month

Like every month, I set myself some targets in my previous income report.

  1. Publish my pairs game as a web app – Successhttp://basicpairs.myappincome.co.uk
  2. Port my pairs game to a React Native app – Success
  3. Try to get the pairs game on the play store – Failure – I want to make a few more tweaks before I try
  4. Publish 2 parts to my third tutorial series – Failure – I worked on two, but only published 1 http://myappincome.co.uk/react-tv-tracker-tutorial-part-1/

Things I achieved or I think are worth celebrating are:

  1. I resigned from my full-time job. I was coasting and that’s not what I want from life.
  2. I created a mailing list for my HTML 5 games and got some subscribers

Target for the next month

  1. Update Basic Pairs so it’s out of the “functional but ugly” category
  2. Try to get Basic Pairs on the play store
  3. Make a chrome extension for Meeting Suite
  4. Start my next HTML 5 Game

React.js Games – Basic Pairs

This site has a new focus, for half of the time, game development. This is announcing my first app from that focus, React.js Games – Basic Pairs.

Introduction

As this is the first post, I want to give a little bit of background.

So why am I doing this? I realised that in my pursuit for extra income, I was spreading myself too thin . Trying to produce something for lots of different audiences is almost impossible. It was wearing me down and achieving nothing.

Yes, the site is about trying to make money from mobile apps. But over the last couple of weeks, I’ve realised that the journey is as important as the result. I enjoyed making the tutorials and was on cloud nine when I heard from someone that they liked my site. Someone even said they liked my writing style and they’re learning from me. #chuffed

Ultimately, with this new approach, I would like to achieve two things:

  1. Learn how to make games for the web and mobiles
  2. Help you learn how to make games for the web and mobiles

That simple. If I make some money off the games I put in the app store, then I see that as a reward for sharing. If it helps someone else release something to the app store, I’ll be very happy. Please let me know if that happens to you.

When you learn something, blog about it. People admire and trust those who educate others.

If this sounds like something you’d be interested in, sign-up.

Sign-Up For Updates

I’m planning to create ever more complex games. For each game, I want to create a blog post explaining any new techniques. I also plan to release the source code. Only those who sign-up to my Game Development mailing list will get the code. You’ll also get access to any updates I make when I add new features.

The source code is then yours to do with whatever you like. Want to re-skin the app and publish it in the app store feel free. I’d love to hear how you use my stuff.

Subscribe to our mailing list

* indicates required



Why Pairs?

We have to start somewhere. Last time I looked into game development – cough 7 years ago cough – I read that you should start simple and build up. It’s the approach I’ve taken so far with React.js, and it seems to be working, so why change.

Why pairs in particular?

  1. It’s simple to play, yet complex enough to be a challenge;
  2. There are no complex timing loops. The events happen in a certain order;
  3. It doesn’t have any “physics” for detect collisions, like pong or knockout.
  4. There are lots of examples out there. So I have lots of inspiration/places to steal ideas from.

There are also quite a few things we can add to our app that I haven’t done before and doesn’t really belong to a game. For example social logins, adding adverts, adding analytics etc. So if we get stuck for features to make the game better, we can still learn stuff that we can use in any app.

Progress So Far

So far, I think I’m making good progress. The code runs on both a React.js web app and an Android React Native app. The vast majority of the code base is shared too. If I had a Mac, I’m sure I could get it to run on a IOS device too.

The web app can be played here http://basicpairs.myappincome.co.uk. The react native app isn’t in the app store yet, but once it is, I’ll update this post.

I think it’s fair to say that it’s more functional than pretty, but we all have to start somewhere.

So far, we have the following features:

  • Single player only
  • Nice animations on the card flipping
  • Level Select
  • Configurable board dimensions
  • Card position is randomised
  • Animated Star Rating on game completion
Basic Pairs So Far

Basic Pairs So Far

I plan to add more things to it.

## Conclusion

I’m excited about this. MyAppIncome will have a focus and I can finally get an app built. There is also a tonne of potential, even for the simplest of games.