57

Philip Shurpik "Architecting React Native app"

  • Upload
    fwdays

  • View
    355

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Philip Shurpik "Architecting React Native app"
Page 2: Philip Shurpik "Architecting React Native app"

About me

Creating magic with React Native in Debitoor/Ciklum :)

Page 3: Philip Shurpik "Architecting React Native app"

What are we doing?

Page 4: Philip Shurpik "Architecting React Native app"

Goals before development started+ Fast to develop with existing JavaScript team

+ Firstly for iOS, then for Android

+ Offline first

+ Mostly native look and feel - animations, visual effects, etc...

Page 5: Philip Shurpik "Architecting React Native app"

Sharing code between platforms

Page 6: Philip Shurpik "Architecting React Native app"

It’s possible to share 70-80-90% of code between platforms

Depending on:

+ Architecture

+ Functionality

+ Third-party plugins usage

Sharing code between platforms

Page 7: Philip Shurpik "Architecting React Native app"

Can be shared

+ Business logic+ Container components

Sharing code between platformsCan’t be shared

- Platform specific stuff- Different interface

patterns

Page 8: Philip Shurpik "Architecting React Native app"

Can be shared

+ Business logic+ Container components

Sharing code between platformsCan’t be shared

- Platform specific stuff- Different interface

patterns

It depends...

● Code that works with plugins● Presentational Components

(depending on design)

Page 9: Philip Shurpik "Architecting React Native app"

Let’s make app architecture

Page 10: Philip Shurpik "Architecting React Native app"

* That’s how React/React Native ecosystem looks like :)

Page 11: Philip Shurpik "Architecting React Native app"

Let’s start from basement

Page 12: Philip Shurpik "Architecting React Native app"

View and Business Logic separation with Redux

tap tap...

User

ContainerComponent

Thanks @andrestaltz for inspiration

State

Reducer

Middleware

Store

Presentational Components

View

Actions

Reducer

API

Render data

Page 13: Philip Shurpik "Architecting React Native app"

But…Sometimes...

Page 14: Philip Shurpik "Architecting React Native app"
Page 15: Philip Shurpik "Architecting React Native app"

But not all apps are working offline...

Page 16: Philip Shurpik "Architecting React Native app"

And even don’t forget your maps route screenshot

Page 17: Philip Shurpik "Architecting React Native app"

...we are offline

tap tap...

User

ContainerComponent

State

Reducer

Middleware

Store

Presentational Components

View

Actions

Reducer

API

Render

?

?

Page 18: Philip Shurpik "Architecting React Native app"

We can solve a lot of problems it in few lines of code+ Persist store state on each change to AsyncStorage

+ Rehydrate store on App Startconst store = createStore(reducer, compose( applyMiddleware(/* ... some middleware */), autoRehydrate()));

Using redux-persist enhancer

persistStore(store, {storage: AsyncStorage});

Page 19: Philip Shurpik "Architecting React Native app"

Redux-persist

Persist store state on each change to AsyncStorage

ContainerComponent State

Reducer

Middleware

Store

Presentational Components

View

Reducer

DeviceAsyncStorageRender

Actions

Page 20: Philip Shurpik "Architecting React Native app"

Redux-persist

Auto rehydrate store on Application start

ContainerComponent State

Reducer

Middleware

Store

Presentational Components

View

Reducer

DeviceAsyncStorage

InitialRender

Page 21: Philip Shurpik "Architecting React Native app"

Actually we received offline-first for viewing data

Let’s improve :)

Page 22: Philip Shurpik "Architecting React Native app"

Viewing data offline

tap tap...

User

ContainerComponent

Store

Presentational Components

View

Actions

API

Renderexisting data

Adding “offline”

label

Redux-persist

State

Reducer

Middleware

Reducer

Marking data as

outdated

Page 23: Philip Shurpik "Architecting React Native app"

Optimistically render

new data

Creating data offline (optimistic ui)

tap tap...

User

ContainerComponent

Store

Presentational Components

View

Actions

API

Adding “not sync”

label

Redux-persist

State

Reducer

Middleware

Reducer

Marking data as not

synchronised

Page 24: Philip Shurpik "Architecting React Native app"

Hints

Generate item Ids on client

Page 25: Philip Shurpik "Architecting React Native app"

Hints

If you have some data dependencies

invoice depending on client and product

make simple dependency tree for synchronisation order

Page 26: Philip Shurpik "Architecting React Native app"

Hints

Use storage version to not break anything while updating app

Page 27: Philip Shurpik "Architecting React Native app"

Hints

Offline-first editing of existing data is much more complicated:

+ Deal with conflicts+ Sync challenges+ Multiple users challenges

* Do it only if it’s one of the main selling points of your app

Page 28: Philip Shurpik "Architecting React Native app"

Navigation

Page 29: Philip Shurpik "Architecting React Native app"

Navigator

NavigatorIOS

NavigationExperimentalreact-native-router-flux

react-native-navigation

ex-navigation

ex-navigatorreact-native-router

react-router-nativereact-native-simple-router

react-native-controllers

Page 30: Philip Shurpik "Architecting React Native app"

Navigation approachesJS-based Navigation

● Navigator

● NavigationExperimental

● react-native-router-flux

● ex-navigation

● ...

Native Navigation

● NavigatorIOS

● react-native-navigation

(wix)

● airbnb solution (not yet

opensourced)

Page 31: Philip Shurpik "Architecting React Native app"

Pros:+ Works with all latest RN versions+ Declarative approach:

<Router createReducer={reducerCreate}><Scene key="loginPage" component={LoginPage} title="Login"/>...

</Router>+ Can be easily debugged (it’s just JS code)+ Has good custom extensions support

React-native-router-flux

Page 32: Philip Shurpik "Architecting React Native app"

Cons:- Bad documentation- Non native JS animations, non native styles- Unable to smoothly integrate with existing IOS/Android apps

React-native-router-flux

Page 33: Philip Shurpik "Architecting React Native app"

Pros:+ Native user experience for Android and IOS platforms+ Developed and supported by Wix

Cons:- You need to know Objective C/Java to debug it/fix issue- Hard to implement something really custom- Limited React Native version support

(stable version supports 0.25.1 and experimental 0.37.0)

React-native-navigation

Page 34: Philip Shurpik "Architecting React Native app"

Performance hints

Page 35: Philip Shurpik "Architecting React Native app"

React Native Threads CommunicationJS Thread

(JavaScriptCore) Native Thread UI (Main) Thread

AsyncBridge

Process Serialize Deserialize

Process

RenderLong

processBecomes not responsive

Process

Page 36: Philip Shurpik "Architecting React Native app"

How to improve+ Use shouldComponentUpdate - avoid not needed rendering

(and bridging from JS to UI thread)

+ Run calculations after animations finish with InteractionManager.runAfterInteractions

+ Offload animations to UI Thread with Layout Animation

+ If everything is completely wrong - write Native code (we haven’t experienced such situations)

Page 37: Philip Shurpik "Architecting React Native app"

Going to production - expected path

Write some JS code

Page 38: Philip Shurpik "Architecting React Native app"

Going to production - actually

Write some JS code

Tests and CI setup example at: https://git.io/rnstk

Page 39: Philip Shurpik "Architecting React Native app"

What we need besides JS code● Javascript tests: Unit and components

Page 40: Philip Shurpik "Architecting React Native app"

Unit tests - exampledescribe('auth.reducer', () => { it('should set token on login success', () => { const action = { type: types.AUTH_LOGIN_SUCCESS, payload: {token: '111'} };

expect(auth(INITIAL_STATE, action)).to.be.deep.equal({ ...INITIAL_STATE, token: '111', loading: false }); });});

Page 41: Philip Shurpik "Architecting React Native app"

Components testing

+ enzyme

+ react-native-mock

+ chai-enzyme

Page 42: Philip Shurpik "Architecting React Native app"

Components tests with Enzyme - exampledescribe('Button.spec.js', () => { let wrapper, pressHandler; beforeEach(() => { pressHandler = sinon.stub(); wrapper = shallow(<Button onPress={pressHandler}>text</Button>); }); it('should render text in button', () => { const text = wrapper.find(Text).first(); expect(text).to.have.prop('children', 'text'); }); it('should handle press', () => { wrapper.simulate('Press'); expect(pressHandler).to.have.been.calledOnce; });});

Page 43: Philip Shurpik "Architecting React Native app"

Integrational (end to end) tests● Javascript tests: Unit and components

● Integrational (end to end) tests:

○ Write in JavaScript - yeah, we are JS developers! :)

○ Run app on simulator

○ Login (check API work)

○ Went through main functionality and check that it works

Page 44: Philip Shurpik "Architecting React Native app"

Appium - architecture● Uses Selenium Webdriver

● Appium is an HTTP server that creates and handles WebDriver sessions

● Appium starts “test case” on device that spawns a server and listen for

proxied commands

Appium test

Page 45: Philip Shurpik "Architecting React Native app"

The same tests crossplatform

Page 46: Philip Shurpik "Architecting React Native app"

The same tests crossplatformReact Native uses different props to access elements on iOS and Android.

Hope will be fixed soon:

https://github.com/facebook/react-native/pull/9942

Page 47: Philip Shurpik "Architecting React Native app"

Test Exampleit('should login', () => getDriver() .waitAndClickElement('SignIn') .waitForElement('Login')

.setElementValue('Email', EMAIL) .setElementValue('Password', PASSWORD)

.clickElement('Login') .waitForElement('Dashboard'))

* With using of custom methods created with wd.addPromiseChainMethod

Page 48: Philip Shurpik "Architecting React Native app"

What about automating custom actions?Like:

+ Signin+ Signout+ Redirect to page

example at: https://git.io/rnstk

Page 49: Philip Shurpik "Architecting React Native app"

Automate commands

Appium test

MobileTestRunner

Action Server(serves actions)

Push action

Press execute button

fetch action

get action

dispatch action

example at: https://git.io/rnstk

Page 50: Philip Shurpik "Architecting React Native app"

Continuous delivery

Page 51: Philip Shurpik "Architecting React Native app"

Continuous delivery with Fastlane+ Manage certificates and provision profiles (for iOS)

+ Make app builds (for iOS)

+ Submits Beta builds to TestFlight / PlayStore alpha track

+ Submits Release builds to AppStore / PlayStore

Page 52: Philip Shurpik "Architecting React Native app"

but...- We need to wait before Apple approves our app

- Users do not update their apps for a long time

- If you update app through appstore it resets user reviews :(

- It’s harder to support different versions of app - especially for

supporters :)

We need to be able to update javascript immediately (like on web)

Page 53: Philip Shurpik "Architecting React Native app"

CodePushCloud service with React Native support

Page 54: Philip Shurpik "Architecting React Native app"

CodePushDeploy Code updates directly to

users:

code-push release-react MyApp ios

● JS Bundle

● Image assets

Page 55: Philip Shurpik "Architecting React Native app"

CodePush features● Separate Staging and Production versions

● Promoting updates

○ Partially promoting (like 20%)

○ A/B testing

● Rollback updates

○ Auto-rollback if app crashes

Page 57: Philip Shurpik "Architecting React Native app"

Questions

skype: philipshurpiktwitter: philipshurpik

https://github.com/philipshurpik