Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Crossing platforms with JavaScript & React

Crossing platforms with JavaScript & React

Robert DeLuca

February 07, 2017
Tweet

More Decks by Robert DeLuca

Other Decks in Technology

Transcript

  1. Crossing platforms with
    JavaScript & React

    View Slide

  2. @robdel12

    View Slide

  3. JavaScript is
    EVERYWHERE

    View Slide

  4. Web

    View Slide

  5. Server

    View Slide

  6. iOS

    View Slide

  7. Android

    View Slide

  8. Desktop

    View Slide

  9. View Slide

  10. What is cross platform
    JS?

    View Slide

  11. JS that can run on
    more than one platform

    View Slide

  12. View Slide

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

    View Slide

  14. “The Android app currently doesn’t
    support that”

    View Slide

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

    View Slide

  16. Easier to share code across many
    teams

    View Slide

  17. More team collaboration since there’s
    more overlap

    View Slide

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

    View Slide

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

    View Slide

  20. Consistency is

    View Slide

  21. Cheaper

    View Slide

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

    View Slide

  23. Why not bet on the web?

    View Slide

  24. Native will be better than mobile web
    for a while

    View Slide

  25. Why not take the web tooling & get
    native results?

    View Slide

  26. You are betting on the web

    View Slide

  27. Can’t beat them, join them

    View Slide

  28. I decided to be ambitious

    View Slide

  29. Build an Instagram clone for Web, iOS,
    & Android

    View Slide

  30. Why an Instagram clone?

    View Slide

  31. Use Impagination.js to power an
    Infinite scroll of images

    View Slide

  32. View Slide

  33. Impagination will work on any JS
    codebase

    View Slide

  34. Building infinite scroll in React Native
    with Impagination
    http://bit.ly/reactnativeinfinitescroll

    View Slide

  35. We’ve already used Impagination in
    four different platforms

    View Slide

  36. What else can be shared?

    View Slide

  37. Experiment time

    View Slide

  38. View Slide

  39. Three phases to the
    experiment
    • Planning
    • Implementation
    • Postmortem

    View Slide

  40. Planning

    View Slide

  41. View Slide

  42. The stack
    • React Native
    • React (DOM)
    • Auth0 (authentication)
    • Graph.cool (backend)
    • Impagination (infinite datasets)

    View Slide

  43. 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

    View Slide

  44. Web demo

    View Slide

  45. Implementation

    View Slide

  46. What’s the approach?

    View Slide

  47. Build the web app

    View Slide

  48. Start to build the native app

    View Slide

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

    View Slide

  50. Refactor

    View Slide

  51. ListPage.js

    View Slide

  52. ListPage.js handles both UI & data
    right now

    View Slide

  53. ListPage for native duplicates a lot
    form web ListPage

    View Slide

  54. class ListPage extends React.Component {
    static propTypes = {
    data: React.PropTypes.object,
    }
    state = {
    dataset: null,
    datasetState: null,
    }
    setupImpagination() {}
    componentWillMount() {this.setupImpagination();}
    setCurrentReadOffset = (event) => {}
    render () {
    return (

    useWindowAsScrollContainer>
    {this.state.datasetState.map(record => {
    if (record.isPending && !record.isSettled) {
    return ;
    }
    return ;
    })}


    );
    }
    }
    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

    View Slide

  55. `
    class ListPage extends React.Component {
    static propTypes = {
    data: React.PropTypes.object,
    }
    state = {
    dataset: null,
    datasetState: null,
    }
    setupImpagination() {}
    componentWillMount() {this.setupImpagination();}
    setCurrentReadOffset = (event) => {}
    render () {
    return (
    onScroll={this.setCurrentReadOffset} removeClippedSubviews={true}>
    {this.state.datasetState.map(record => {
    if(record.isPending && !record.isSettled) {
    return ;
    }
    return ;
    })}

    );
    }
    }
    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

    View Slide

  56. Everything but the UI is the same

    View Slide

  57. New structure

    View Slide

  58. Presentation & container components

    View Slide



  59. View Slide

  60. import ListPageView from ‘../components/presentational/ListPageView’;
    class ListPageContainer extends React.Component {
    state = {
    dataset: null,
    datasetState: null,
    }
    setupImpagination() {}
    componentWillMount() {this.setupImpagination();}
    setCurrentReadOffset = (event) => {}
    render () {
    return (
    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);

    View Slide

  61. Make the container component render
    a separate presentation component

    View Slide

  62. Leave setting the readOffset to the
    presentation components

    View Slide

  63. setCurrentReadOffset function is passed
    as a prop from the container component

    View Slide

  64. 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 (

    useWindowAsScrollContainer>
    {this.props.datasetState.map(record => {
    if (record.isPending && !record.isSettled) {
    return ;
    }
    return user={record.content.user} />;
    })}


    );
    }
    }
    export default ListPageView;
    Web presentation component

    View Slide

  65. 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 (
    onScroll={this.setCurrentReadOffset} removeClippedSubviews={true}>
    {this.props.datasetState.map(record => {
    if(record.isPending && !record.isSettled) {
    return ;
    }
    return user={record.content.user} />;
    })}

    );
    }
    }
    export default ListPageView;

    View Slide

  66. This theme continues throughout the
    entire app

    View Slide



  67. onEnter={this.requireAuth.bind(this)} />







    } />

    View Slide

  68. Native app demo

    View Slide

  69. Postmortem

    View Slide

  70. Building the apps in time was hard…

    View Slide

  71. View Slide

  72. View Slide

  73. Figuring out what code is shareable

    View Slide

  74. Figuring out how to make that code
    shareable

    View Slide

  75. React Router is neat & works cross
    platform
    There are different imports for React Native
    & React

    View Slide

  76. View Slide

  77. Auth0 was very easy to implement on
    both platforms.
    There are different APIs for React Native &
    React

    View Slide

  78. AsyncStorage vs localStorage

    View Slide

  79. What all ended up being shared?

    View Slide

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

    View Slide

  81. Beyond login mostly everything else is
    the same

    View Slide

  82. The UI changed but not the business
    logic

    View Slide

  83. Key takeaways

    View Slide

  84. We’re in a post DOM world

    View Slide

  85. Write JavaScript interaction models

    View Slide

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

    View Slide

  87. “It’s just JavaScript”

    View Slide

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

    View Slide

  89. React makes this very easy thanks to
    React & React Native

    View Slide

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

    View Slide

  91. Write one container component and
    many UI components

    View Slide

  92. The core of this app is shared

    View Slide

  93. That’s a cost savings

    View Slide

  94. I own this entire product & its 3
    platforms

    View Slide

  95. In 2 weeks I was able do all of this

    View Slide

  96. Cross platform JS FTW

    View Slide

  97. Instagram also agrees with me
    https://engineering.instagram.com/react-native-at-instagram-
    dd828a9a90c7#.i364vchox

    View Slide

  98. View Slide

  99. If this kind of stuff interests you

    View Slide

  100. We’re hiring!

    View Slide

  101. Thanks!
    @robdel12

    View Slide