crossing platforms with javascript & react

101
Crossing platforms with JavaScript & React

Upload: robert-deluca

Post on 21-Mar-2017

54 views

Category:

Engineering


4 download

TRANSCRIPT

Page 1: Crossing platforms with JavaScript & React

Crossing platforms with JavaScript & React

Page 2: Crossing platforms with JavaScript & React

@robdel12

Page 3: Crossing platforms with JavaScript & React

JavaScript is EVERYWHERE

Page 4: Crossing platforms with JavaScript & React

Web

Page 5: Crossing platforms with JavaScript & React

Server

Page 6: Crossing platforms with JavaScript & React

iOS

Page 7: Crossing platforms with JavaScript & React

Android

Page 8: Crossing platforms with JavaScript & React

Desktop

Page 9: Crossing platforms with JavaScript & React
Page 10: Crossing platforms with JavaScript & React

What is cross platform JS?

Page 11: Crossing platforms with JavaScript & React

JS that can run on more than one platform

Page 12: Crossing platforms with JavaScript & React
Page 13: Crossing platforms with JavaScript & React

“Why did the iOS team implement it like this?”

Page 14: Crossing platforms with JavaScript & React

“The Android app currently doesn’t support that”

Page 15: Crossing platforms with JavaScript & React

https://twitter.com/dan_abramov/status/812047645732651009

Page 16: Crossing platforms with JavaScript & React

Easier to share code across many teams

Page 17: Crossing platforms with JavaScript & React

More team collaboration since there’s more overlap

Page 18: Crossing platforms with JavaScript & React

It allows teams to own products & not be separated by technology

Page 19: Crossing platforms with JavaScript & React

TL;DR your team now owns the iOS, Android, and (maybe) web apps.

Page 20: Crossing platforms with JavaScript & React

Consistency is 🔑

Page 21: Crossing platforms with JavaScript & React

Cheaper

Page 22: Crossing platforms with JavaScript & React

If you can build iOS & Android apps in the same code base it should be cheaper

Page 23: Crossing platforms with JavaScript & React

Why not bet on the web?

Page 24: Crossing platforms with JavaScript & React

Native will be better than mobile web for a while

Page 25: Crossing platforms with JavaScript & React

Why not take the web tooling & get native results?

Page 26: Crossing platforms with JavaScript & React

You are betting on the web

Page 27: Crossing platforms with JavaScript & React

Can’t beat them, join them

Page 28: Crossing platforms with JavaScript & React

I decided to be ambitious

Page 29: Crossing platforms with JavaScript & React

Build an Instagram clone for Web, iOS, & Android

Page 30: Crossing platforms with JavaScript & React

Why an Instagram clone?

Page 31: Crossing platforms with JavaScript & React

Use Impagination.js to power an Infinite scroll of images

Page 32: Crossing platforms with JavaScript & React
Page 33: Crossing platforms with JavaScript & React

Impagination will work on any JS codebase

Page 34: Crossing platforms with JavaScript & React

Building infinite scroll in React Native with Impagination

http://bit.ly/reactnativeinfinitescroll

Page 35: Crossing platforms with JavaScript & React

We’ve already used Impagination in four different platforms

Page 36: Crossing platforms with JavaScript & React

What else can be shared?

Page 37: Crossing platforms with JavaScript & React

Experiment time

Page 38: Crossing platforms with JavaScript & React
Page 39: Crossing platforms with JavaScript & React

Three phases to the experiment

• Planning

• Implementation

• Postmortem

Page 40: Crossing platforms with JavaScript & React

Planning

Page 41: Crossing platforms with JavaScript & React
Page 42: Crossing platforms with JavaScript & React

🥞The stack🥞

• React Native

• React (DOM)

• Auth0 (authentication)

• Graph.cool (backend)

• Impagination (infinite datasets)

Page 43: Crossing platforms with JavaScript & React

What should the app do?

• Login / Sign up

• See your profile & images you’ve posted

• Edit your profile

• Post a new photo

• Main list feed showing everyones posts

Page 44: Crossing platforms with JavaScript & React

Web demo

Page 45: Crossing platforms with JavaScript & React

Implementation

Page 46: Crossing platforms with JavaScript & React

What’s the approach?

Page 47: Crossing platforms with JavaScript & React

Build the web app

Page 48: Crossing platforms with JavaScript & React

Start to build the native app

Page 49: Crossing platforms with JavaScript & React

Realize I’ve already solved these problems in the web app

Page 50: Crossing platforms with JavaScript & React

Refactor

Page 51: Crossing platforms with JavaScript & React

ListPage.js

Page 52: Crossing platforms with JavaScript & React

ListPage.js handles both UI & data right now

Page 53: Crossing platforms with JavaScript & React

ListPage for native duplicates a lot form web ListPage

Page 54: Crossing platforms with JavaScript & React

class ListPage extends React.Component { static propTypes = { data: React.PropTypes.object, } state = { dataset: null, datasetState: null, } setupImpagination() {}

componentWillMount() {this.setupImpagination();}

setCurrentReadOffset = (event) => {}

render () { return ( <div style={{maxWidth: "600px", margin: "0 auto", padding: "20px 0"}}> <Infinite elementHeight={ITEM_HEIGHT} handleScroll={this.setCurrentReadOffset} useWindowAsScrollContainer> {this.state.datasetState.map(record => { if (record.isPending && !record.isSettled) { return <LoadingPost key={Math.random()} />; }

return <Photo key={record.content.id} photo={record.content} user={record.content.user} />; })} </Infinite> </div> ); } }

const FeedQuery = gql`query($skip: Int!, $first: Int!) { allPhotos(orderBy: createdAt_DESC, first: $first, skip: $skip) { } }`;

export default graphql(FeedQuery, {options: {variables: { skip: 0, first: PAGE_SIZE }}})(ListPage);

Web ListPage.js

Page 55: Crossing platforms with JavaScript & React

`

class ListPage extends React.Component { static propTypes = { data: React.PropTypes.object, } state = { dataset: null, datasetState: null, } setupImpagination() {}

componentWillMount() {this.setupImpagination();}

setCurrentReadOffset = (event) => {}

render () { return ( <ScrollView style={{flex: 1}} scrollEventThrottle={300} onScroll={this.setCurrentReadOffset} removeClippedSubviews={true}> {this.state.datasetState.map(record => { if(record.isPending && !record.isSettled) { return <LoadingPost key={Math.random()}/>; }

return <Photo key={record.content.id} photo={record.content} user={record.content.user} />; })} </ScrollView> ); } }

const FeedQuery = gql`query($skip: Int!, $first: Int!) { allPhotos(orderBy: createdAt_DESC, first: $first, skip: $skip) { } }`;

export default graphql(FeedQuery, {options: {variables: { skip: 0, first: PAGE_SIZE }}})(ListPage);

Native ListPage.js

Page 56: Crossing platforms with JavaScript & React

Everything but the UI is the same

Page 57: Crossing platforms with JavaScript & React

New structure

Page 58: Crossing platforms with JavaScript & React

Presentation & container components

Page 59: Crossing platforms with JavaScript & React

<IndexRoute component={ListPageContainer} /> <Route path='feed' component={ListPageContainer} />

Page 60: Crossing platforms with JavaScript & React

import ListPageView from ‘../components/presentational/ListPageView’;

class ListPageContainer extends React.Component { state = { dataset: null, datasetState: null, } setupImpagination() {}

componentWillMount() {this.setupImpagination();}

setCurrentReadOffset = (event) => {}

render () { return ( <ListPageView setCurrentReadOffset={this.setCurrentReadOffset} datasetState={this.state.datasetState} />; ); } }

const FeedQuery = gql`query($skip: Int!, $first: Int!) { allPhotos(orderBy: createdAt_DESC, first: $first, skip: $skip) { } }`;

export default graphql(FeedQuery, {options: {variables: { skip: 0, first: PAGE_SIZE }}})(ListPage);

Page 61: Crossing platforms with JavaScript & React

Make the container component render a separate presentation component

Page 62: Crossing platforms with JavaScript & React

Leave setting the readOffset to the presentation components

Page 63: Crossing platforms with JavaScript & React

setCurrentReadOffset function is passed as a prop from the container component

Page 64: Crossing platforms with JavaScript & React

t

import React, { Component } from 'react'; import Infinite from 'react-infinite'; import Photo from '../presentational/Photo'; import LoadingPost from '../presentational/LoadingPost';

const ITEM_HEIGHT = 600; const HEADER_HEIGHT = 80;

class ListPageView extends Component { setCurrentReadOffset = (event) => { let currentItemIndex = Math.ceil((window.scrollY - HEADER_HEIGHT) / ITEM_HEIGHT);

this.props.setCurrentReadOffset(currentItemIndex); }

render() { return ( <div style={{maxWidth: "600px", margin: "0 auto", padding: "20px 0"}}> <Infinite elementHeight={ITEM_HEIGHT} handleScroll={this.setCurrentReadOffset} useWindowAsScrollContainer> {this.props.datasetState.map(record => { if (record.isPending && !record.isSettled) { return <LoadingPost key={Math.random()} />; }

return <Photo key={record.content.id} photo={record.content} user={record.content.user} />; })} </Infinite> </div> ); } }

export default ListPageView;

Web presentation component

Page 65: Crossing platforms with JavaScript & React

Native presentation component

import React, { Component } from 'react'; import Photo from '../presentational/Photo'; import LoadingPost from '../presentational/LoadingPost'; import { ScrollView } from 'react-native';

const ITEM_HEIGHT = 485;

class ListPageView extends Component { setCurrentReadOffset = (event) => { let currentOffset = Math.floor(event.nativeEvent.contentOffset.y); let currentItemIndex = Math.ceil(currentOffset / ITEM_HEIGHT);

this.props.setCurrentReadOffset(currentItemIndex); }

render() { return ( <ScrollView style={{flex: 1}} scrollEventThrottle={300} onScroll={this.setCurrentReadOffset} removeClippedSubviews={true}> {this.props.datasetState.map(record => { if(record.isPending && !record.isSettled) { return <LoadingPost key={Math.random()}/>; }

return <Photo key={record.content.id} photo={record.content} user={record.content.user} />; })} </ScrollView> ); } }

export default ListPageView;

Page 66: Crossing platforms with JavaScript & React

This theme continues throughout the entire app

Page 67: Crossing platforms with JavaScript & React

<IndexRoute component={ListPageContainer} /> <Route path='feed' component={ListPageContainer} /> <Route path='new' component={CreatePostContainer} onEnter={this.requireAuth.bind(this)} /> <Route path='signup' component={CreateUserContainer} /> <Route path='profile' component={UserProfileContainer} > <IndexRoute component={UserProfileContainer} /> <Route path='edit' component={EditProfileContainer} /> </Route> <Route path='logout' component={() => <Logout logout={this.handleToken.bind(this)} /> } />

Page 68: Crossing platforms with JavaScript & React

Native app demo

Page 69: Crossing platforms with JavaScript & React

Postmortem

Page 70: Crossing platforms with JavaScript & React

Building the apps in time was hard…

Page 71: Crossing platforms with JavaScript & React
Page 72: Crossing platforms with JavaScript & React
Page 73: Crossing platforms with JavaScript & React

Figuring out what code is shareable

Page 74: Crossing platforms with JavaScript & React

Figuring out how to make that code shareable

Page 75: Crossing platforms with JavaScript & React

React Router is neat & works cross platform

There are different imports for React Native & React

Page 76: Crossing platforms with JavaScript & React
Page 77: Crossing platforms with JavaScript & React

Auth0 was very easy to implement on both platforms.

There are different APIs for React Native & React

Page 78: Crossing platforms with JavaScript & React

AsyncStorage vs localStorage

Page 79: Crossing platforms with JavaScript & React

What all ended up being shared?

Page 80: Crossing platforms with JavaScript & React

✅ List feed✅ User profile✅ Edit user profile✅ Sign up✅ New post

Page 81: Crossing platforms with JavaScript & React

Beyond login mostly everything else is the same

Page 82: Crossing platforms with JavaScript & React

The UI changed but not the business logic

Page 83: Crossing platforms with JavaScript & React

Key takeaways

Page 84: Crossing platforms with JavaScript & React

We’re in a post DOM world

Page 85: Crossing platforms with JavaScript & React

Write JavaScript interaction models

Page 86: Crossing platforms with JavaScript & React

The UI framework will change but the underlying model driving it won’t

Page 87: Crossing platforms with JavaScript & React

“It’s just JavaScript”

Page 88: Crossing platforms with JavaScript & React

We get stronger libraries by increasing the number of users & contributors.

Page 89: Crossing platforms with JavaScript & React

React makes this very easy thanks to React & React Native

Page 90: Crossing platforms with JavaScript & React

I was able to share the same five container components across three different platforms

Page 91: Crossing platforms with JavaScript & React

Write one container component and many UI components

Page 92: Crossing platforms with JavaScript & React

The core of this app is shared

Page 93: Crossing platforms with JavaScript & React

That’s a cost savings

Page 94: Crossing platforms with JavaScript & React

I own this entire product & its 3 platforms

Page 95: Crossing platforms with JavaScript & React

In 2 weeks I was able do all of this

Page 96: Crossing platforms with JavaScript & React

Cross platform JS FTW

Page 97: Crossing platforms with JavaScript & React

Instagram also agrees with mehttps://engineering.instagram.com/react-native-at-instagram-

dd828a9a90c7#.i364vchox

Page 98: Crossing platforms with JavaScript & React
Page 99: Crossing platforms with JavaScript & React

If this kind of stuff interests you

Page 100: Crossing platforms with JavaScript & React

We’re hiring!

Page 101: Crossing platforms with JavaScript & React

Thanks!@robdel12