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

  2. iOS

  3. If you can build iOS & Android apps in the

    same code base it should be cheaper
  4. The stack • React Native • React (DOM) • Auth0

    (authentication) • Graph.cool (backend) • Impagination (infinite datasets)
  5. 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
  6. 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
  7. ` 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
  8. 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);
  9. 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
  10. 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;
  11. <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)} /> } />
  12. React Router is neat & works cross platform There are

    different imports for React Native & React
  13. Auth0 was very easy to implement on both platforms. There

    are different APIs for React Native & React