How to implement an app for web, iOS, Android with virtually same code and all the proper bells and whistles: Analytics, Sharing buttons, AdSense/AdMob ads.
Presented at PiterJS meetup on 09 Feb 2017
12. Google Analytics: Mobile
react-native-google-analytics-bridge
• Worked as simple as
const GA = require('react-native-google-
analytics-bridge');
const GA_TRACKER_ID = Platform.OS === 'ios'
? 'UA-76217125-6' : 'UA-76217125-5';
GA.setTrackerId( GA_TRACKER_ID );
GA.trackEvent('general', 'app: activated');
https://twitter.com/AgileArtem
13. Mobile Ads: Google AdMob
react-native-admob
Converting default React Native iOS project to pods/workspace
can be challenging, but then the usage is super-simple
import { AdMobBanner } from 'react-native-admob’;
<AdMobBanner
style={appStyle.bottomBanner}
bannerSize={"smartBannerPortrait"}
adUnitID={"ca-app-pub-
6248714847105943/1045980532"}
didFailToReceiveAdWithError={this.bannerError}
/>
https://twitter.com/AgileArtem
14. Redux and Redux Dev Tools
• Redux (or Flux if you like) could be the best
part of React practice actually
https://twitter.com/AgileArtem
16. Redux. Good parts
• Redux is awesome.
• Debugging dumb structures, tracing changes
message by message and time traveling is
simple and efficient
• Definitely use Redux Dev Tools (e.g. as a
Chrome extension)
https://twitter.com/AgileArtem
17. Redux. Complexities
• Making Redux, routing and Local Storage like
each other was pain in the bottom and rain
dances
– There is logic certainly, but you’ll either need to learn
a lot of it or dance around and hope
– Or clone my solution, but be aware it’s coding by
accident
• Modifying several files in the different parts of
code base (action creator, reducer, handler) for
just passing same stuff around is a lot of error
prone typing.
– Consider ducks approach – all the code about one bit
of functionality together
https://twitter.com/AgileArtem
18. Redux: more mistakes
• Do not store UI state (screen size) or
computable data (final price) in the model
• Use memoizable redux selectors for it (e.g.
reselect).
– Looks the same, feels the same, but you do not
pollute the model with the data to keep in sync
https://twitter.com/AgileArtem
19. Immutable.JS
const calcedPaymentState =
preUpdatedState.setIn(['paymentOptions', 'eTicket',
'totalCost'], newETicketCost)
• State that’s guaranteed to be immutable is way easier to
debug
• But not all the components are ready for it out of the box and
want to see plain JS objects (I had issues with browserHistory I
think)
• And on a small research-like app you might not see benefits of
immutability yet while you might hit the integration obstacles
https://twitter.com/AgileArtem
20. Routing and browse and sharable urls
import { Router, Route, IndexRoute, browserHistory, useRouterHistory } from 'react-
router';
import { routerMiddleware, syncHistoryWithStore, routerReducer, push } from 'react-
router-redux';
import createBrowserHistory from 'history/lib/createBrowserHistory';
const queryString = require('query-string');
const history = syncHistoryWithStore(browserHistory, store,
{selectLocationState: (state) => {
const r = state.getIn(['metadata', 'routing']);
return r || '/';
}});
const routedState = state.setIn(['metadata', 'routing'], {
locationBeforeTransitions: {
pathname: '/',
search: searchString,
query: {},
hash: ''
}
}) https://twitter.com/AgileArtem
21. Routing and browse and sharable urls
• React Router is okay, browserHistory is okay, storing routing in a
storage is okay, but making it work together is tough
– Especially if some more middleware is involved: Redux Dev Tools
• I used query string as the initial boss that commanded the state
that was setting up the routing
– Then state updates are changing the browserHistory-specific keys.
browserHistory was updating the address bar
• And there are WebKit bugs features. You cannot update URL too
often
• Use my solution if you just want things to work
– Yet it’s programming by accident
https://twitter.com/AgileArtem
22. Structuring controls for testing
• Simple, isolates core part for testability, but I didn’t use
much testing in the end
– Started from awesome tutorial by a Finn
@teropahttp://teropa.info/blog/2015/09/10/full-stack-
redux-tutorial.html
export class InputBlock extends React.Component {
constructor(props) {
…
export const InputBlockContainer = connect(
mapStateToProps,
actionCreators
)(InputBlock);
https://twitter.com/AgileArtem
23. Using template for injecting stuff into
the web root
var HtmlWebpackPlugin = require('html-webpack-plugin');
…
new HtmlWebpackPlugin({
inject: false,
template: 'src/web/index.ejs',
googleAnalytics: {
trackingId: 'UA-76217125-4',
pageViewOnLoad: true
},
…
<% if
(htmlWebpackPlugin.options.googleAnalytics.trackingId) {
%>
ga('create', '<%=
htmlWebpackPlugin.options.googleAnalytics.trackingId%>',
'auto'); https://twitter.com/AgileArtem
25. Portrait-Landscape layouting and
*cascading* styles
react-native-media-queries
• Works, but you may need to track rotation yourself
• Not exactly full. E.g. no difference between min-width and
min-device-width
const baseStyle = {
podorozhnikAppView: {
flexDirection: 'column',
…
export const appStyle = createStyles(
baseStyle,
maxHeight(400, {
optionsBlock: {
marginTop: 0,
…
https://twitter.com/AgileArtem
27. Autostoring redux data to localStorage
import * as storage from 'redux-storage';
import createEngine from 'redux-storage-engine-
reactnativeasyncstorage';
import merger from 'redux-storage-merger-
immutablejs';
• Just works
• Mobile app only implementation
• Immutable JS was an issue here. As restoring
data was trying to overwrite the model
https://twitter.com/AgileArtem
28. WHAT NOT TO FOLLOW
https://twitter.com/AgileArtem
29. WebViews on the app side for the web
services
• I tried one for disqus
• Bad idea. Slow, error prone, hard to debug
and fix
https://twitter.com/AgileArtem
30. A note on testing
• I love automated structured testing so much that for
Jolla Sailfish OS I baked HelloWorld wizard that
includes testing of engine, UI, C++, JavaScript, whatnot.
• Started in full testing more in ReactJS/Native and..
• Nearly completely dropped in the end
• For the relatively simple UI-intensive project Redux
with its DevTools lets you identify and fix issues faster
than tests would have prevented them
• In a bigger project with collaborators and less core
research I’d use auto testing though
https://twitter.com/AgileArtem
31. iPad layout
• Didn’t work
• Seems to be possible, but solution I used
results in the iPhone mode
https://twitter.com/AgileArtem
32. Same code for React app on the web,
iOS, Android
• Yes
• No
• Maybe
• You are only going to really benefit from the
logic part only
• iOS and Android are close enough for sharing
almost everything
https://twitter.com/AgileArtem