Upload
fwdays
View
355
Download
0
Embed Size (px)
Citation preview
About me
Creating magic with React Native in Debitoor/Ciklum :)
What are we doing?
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...
Sharing code between platforms
It’s possible to share 70-80-90% of code between platforms
Depending on:
+ Architecture
+ Functionality
+ Third-party plugins usage
Sharing code between platforms
Can be shared
+ Business logic+ Container components
Sharing code between platformsCan’t be shared
- Platform specific stuff- Different interface
patterns
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)
Let’s make app architecture
* That’s how React/React Native ecosystem looks like :)
Let’s start from basement
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
But…Sometimes...
But not all apps are working offline...
And even don’t forget your maps route screenshot
...we are offline
tap tap...
User
ContainerComponent
State
Reducer
Middleware
Store
Presentational Components
View
Actions
Reducer
API
Render
?
?
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});
Redux-persist
Persist store state on each change to AsyncStorage
ContainerComponent State
Reducer
Middleware
Store
Presentational Components
View
Reducer
DeviceAsyncStorageRender
Actions
Redux-persist
Auto rehydrate store on Application start
ContainerComponent State
Reducer
Middleware
Store
Presentational Components
View
Reducer
DeviceAsyncStorage
InitialRender
Actually we received offline-first for viewing data
Let’s improve :)
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
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
Hints
Generate item Ids on client
Hints
If you have some data dependencies
invoice depending on client and product
make simple dependency tree for synchronisation order
Hints
Use storage version to not break anything while updating 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
Navigation
Navigator
NavigatorIOS
NavigationExperimentalreact-native-router-flux
react-native-navigation
ex-navigation
ex-navigatorreact-native-router
react-router-nativereact-native-simple-router
react-native-controllers
Navigation approachesJS-based Navigation
● Navigator
● NavigationExperimental
● react-native-router-flux
● ex-navigation
● ...
Native Navigation
● NavigatorIOS
● react-native-navigation
(wix)
● airbnb solution (not yet
opensourced)
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
Cons:- Bad documentation- Non native JS animations, non native styles- Unable to smoothly integrate with existing IOS/Android apps
React-native-router-flux
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
Performance hints
React Native Threads CommunicationJS Thread
(JavaScriptCore) Native Thread UI (Main) Thread
AsyncBridge
Process Serialize Deserialize
Process
RenderLong
processBecomes not responsive
Process
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)
Going to production - expected path
Write some JS code
Going to production - actually
Write some JS code
Tests and CI setup example at: https://git.io/rnstk
What we need besides JS code● Javascript tests: Unit and components
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 }); });});
Components testing
+ enzyme
+ react-native-mock
+ chai-enzyme
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; });});
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
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
The same tests crossplatform
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
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
What about automating custom actions?Like:
+ Signin+ Signout+ Redirect to page
example at: https://git.io/rnstk
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
Continuous delivery
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
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)
CodePushCloud service with React Native support
CodePushDeploy Code updates directly to
users:
code-push release-react MyApp ios
● JS Bundle
● Image assets
CodePush features● Separate Staging and Production versions
● Promoting updates
○ Partially promoting (like 20%)
○ A/B testing
● Rollback updates
○ Auto-rollback if app crashes
LinksReact Native Starter Kit:
https://github.com/philipshurpik/react-native-starter-kit
Performance tuning:
https://medium.com/@talkol/performance-limitations-of-react-native-and-how-to-overcome-them-947630d7f440#.2dsdud7yr
https://facebook.github.io/react-native/docs/android-ui-performance.html
Questions
skype: philipshurpiktwitter: philipshurpik
https://github.com/philipshurpik