React Native - Workshop

Preview:

Citation preview

REACT NATIVE

REACT NATIVEWorkshop

Fellipe Chagas@chagasaway

Ajudamos grandes empresas e startups a focarem em seu negócio

entregando tecnologia

DESENVOLVIMENTO NATIVO

DESENVOLVIMENTO NATIVO

DESENVOLVIMENTO NATIVO

DESENVOLVIMENTO NATIVO

DESENVOLVIMENTO NATIVO

DESENVOLVIMENTO HÍBRIDO

DESENVOLVIMENTO HÍBRIDO

DESENVOLVIMENTO HÍBRIDO

DESENVOLVIMENTO HÍBRIDO

DESENVOLVIMENTO HÍBRIDO

DESENVOLVIMENTO HÍBRIDO

DESENVOLVIMENTO HÍBRIDO

DESENVOLVIMENTO HÍBRIDO

DESENVOLVIMENTO HÍBRIDO

FRAMEWORKS

FRAMEWORKS

FRAMEWORKS

FRAMEWORKS

FRAMEWORKS

FRAMEWORKS

FRAMEWORKS

35.350 stars 897 contribuidores

e crescendo…

REACT

REACT

REACT

REACT

REACT

e milhares de outros…

REACTCOMPONENTES

REACTCOMPONENTES

TUDO PODE SER JAVASCRIPT

REACT

VIRTUAL DOM

COMPONENTES

TUDO PODE SER JAVASCRIPT

COMPONENTES

APP

COMPONENTESHEADER

TABS

CARD

CARD

COMPONENTESHEADER

TABS

CARD

CARD IMAGEUSER AVATAR

CARD TEXT

CARD IMAGEUSER AVATAR

CARD TEXT

COMPONENTESHEADER

TABS

CARD

CARD IMAGEUSER AVATAR

CARD TEXT

CARD IMAGEUSER AVATAR

CARD TEXT

HEADER

TABS

ACCOUNT INFO

USER AVATAR

ACCOUNT SETTINGS

CARD TEXT

CARD IMAGEUSER

AVATAR

COMPONENTES

CARD TEXT

CARD IMAGEUSER

AVATAR

COMPONENTES

import React, { Component, StyleSheet, PropTypes, Image, } from 'react-native'

export default class Avatar extends Component { constructor(props) { super(props) }

render() { return ( <Image source={this.props.image} style={styles.image} /> ) } }

Avatar.propTypes = { image: PropTypes.object.isRequired, }

const styles = StyleSheet.create({ image: { width: 30, height: 30, borderRadius: 15 }, })

CARD IMAGEUSER

AVATAR

CARD TEXT

COMPONENTES

COMPONENTEScomponentWillMount

COMPONENTEScomponentWillMount

componentDidMount

COMPONENTEScomponentWillMount

componentDidMount

componentWillReceiveProps

COMPONENTEScomponentWillMount

componentDidMount

componentWillReceiveProps

shouldComponentUpdate

COMPONENTEScomponentWillMount

componentDidMount

componentWillReceiveProps

shouldComponentUpdate

componentWillUpdate

COMPONENTEScomponentWillMount

componentDidMount

componentWillReceiveProps

shouldComponentUpdate

componentWillUpdate

componentDidUpdate

COMPONENTEScomponentWillMount

componentDidMount

componentWillReceiveProps

shouldComponentUpdate

componentWillUpdate

componentDidUpdate

componentWillUnmount

COMPONENTEScomponentWillMount

componentDidMount

componentWillReceiveProps

shouldComponentUpdate

componentWillUpdate

componentDidUpdate

componentWillUnmount

Props

COMPONENTEScomponentWillMount

componentDidMount

componentWillReceiveProps

shouldComponentUpdate

componentWillUpdate

componentDidUpdate

componentWillUnmount

Props &State

Props

REACT

VIRTUAL DOM

COMPONENTES

TUDO PODE SER JAVASCRIPT

TUDO PODE SER JAVASCRIPT

TUDO PODE SER JAVASCRIPT

HTML

import React, { Component, StyleSheet, PropTypes, Image, } from 'react-native'

export default class Avatar extends Component { constructor(props) { super(props) }

render() { return ( <Image source={this.props.image} style={styles.image} /> ) } }

Avatar.propTypes = { image: PropTypes.object.isRequired, }

const styles = StyleSheet.create({ image: { width: 30, height: 30, borderRadius: 15, }, })

import React, { Component, StyleSheet, PropTypes, Image, } from 'react-native'

export default class Avatar extends Component { constructor(props) { super(props) }

render() { return ( <Image source={this.props.image} style={styles.image} /> ) } }

Avatar.propTypes = { image: PropTypes.object.isRequired, }

const styles = StyleSheet.create({ image: { width: 30, height: 30, borderRadius: 15, }, })

TUDO PODE SER JAVASCRIPT

<Image source={this.props.image} style={styles.image}

/>

TUDO PODE SER JAVASCRIPT<Image source={this.props.image}

style={styles.image} />

JSX

TUDO PODE SER JAVASCRIPT<Image source={this.props.image}

style={styles.image} />

JSXlet image = React.createElement(

Image, { source: this.props.image,

style: styles.image })

TUDO PODE SER JAVASCRIPT

<Image source={this.props.image} style={styles.image}

/>

JSX

<img src=‘imagem.png’ style=‘border-radius: 5px’

/>

HTML

CSS

import React, { Component, StyleSheet, PropTypes, Image, } from 'react-native'

export default class Avatar extends Component { constructor(props) { super(props) }

render() { return ( <Image source={this.props.image} style={styles.image} /> ) } }

Avatar.propTypes = { image: PropTypes.object.isRequired, }

const styles = StyleSheet.create({ image: { width: 30, height: 30, borderRadius: 15, }, })

import React, { Component, StyleSheet, PropTypes, Image, } from 'react-native'

export default class Avatar extends Component { constructor(props) { super(props) }

render() { return ( <Image source={this.props.image} style={styles.image} /> ) } }

Avatar.propTypes = { image: PropTypes.object.isRequired, }

const styles = StyleSheet.create({ image: { width: 30, height: 30, borderRadius: 15, }, })

TUDO PODE SER JAVASCRIPT

StyleSheet.create({ image: { width: 30, height: 30, borderRadius: 15, }, })

TUDO PODE SER JAVASCRIPT

StyleSheet.create({ image: { width: 30, height: 30, borderRadius: 15, }, })

StyleSheet

TUDO PODE SER JAVASCRIPT

StyleSheet.create({ image: { width: 30, height: 30, borderRadius: 15, }, })

StyleSheet

.image { width: 30px,

height: 30px, borderRadius: 15px }

CSS

REACT

VIRTUAL DOM

COMPONENTES

TUDO PODE SER JAVASCRIPT

VIRTUAL DOM

HTML DOM

VIRTUAL DOMHTML DOM

JAVASCRIPT

VIRTUAL DOMHTML DOM

JAVASCRIPT

VIRTUAL DOM

VIRTUAL DOM

VIRTUAL DOM

ANDROID DOM

iOS DOM

HTML DOM

VIRTUAL DOMANDROID

DOMiOS

DOMHTML DOM

SONY DOM

SAMSUNG DOM

WINDOWS DOM

BRASTEMP DOM

LG DOM

PHILIPS DOM

REACT NATIVE

COMPONENTESView Image Text Activity

Indicator

Modal Navigator Refresh Control ScrollView

StatusBar Switch ListView TextInput

WebView MapView ProgressBar Android …

APIsAlert Animated AppState BackAndroid

CameraRoll Clipboard DatePicker Android Dimensions

Geolocation Linking NetInfo ToastAndroid

PixelRatio PushNotification IOS Vibration +++

COMUNIDADE

COMUNIDADE

COMUNIDADE

BIBLIOTECAS NATIVAS

BIBLIOTECAS NATIVASBIBLIOTECA NATIVA

REACT NATIVE

BIBLIOTECAS NATIVASBIBLIOTECA NATIVA

REACT NATIVE

BIBLIOTECAS NATIVASBIBLIOTECA NATIVA

REACT NATIVE

BIBLIOTECAS NATIVASBIBLIOTECA NATIVA

REACT NATIVE

REACT NATIVE BRIDGE

'use strict';

var {PayPal} = require('react-native').NativeModules;

var constants = {}; var constantNames = Object.keys(PayPal).filter(p => p == p.toUpperCase()); constantNames.forEach(c => constants[c] = PayPal[c]);

var functions = { paymentRequest(payPalParameters) { return new Promise(function(resolve, reject) { PayPal.paymentRequest(payPalParameters, resolve, reject); }); } };

var exported = {}; Object.assign(exported, constants, functions);

module.exports = exported;

'use strict';

var {PayPal} = require('react-native').NativeModules;

var constants = {}; var constantNames = Object.keys(PayPal).filter(p => p == p.toUpperCase()); constantNames.forEach(c => constants[c] = PayPal[c]);

var functions = { paymentRequest(payPalParameters) { return new Promise(function(resolve, reject) { PayPal.paymentRequest(payPalParameters, resolve, reject); }); } };

var exported = {}; Object.assign(exported, constants, functions);

module.exports = exported;

public class PayPal extends ReactContextBaseJavaModule { @ReactMethod public void paymentRequest( final ReadableMap payPalParameters, final Callback successCallback, final Callback errorCallback ) { final String environment = payPalParameters.getString("environment"); final String clientId = payPalParameters.getString("clientId"); final String price = payPalParameters.getString("price"); final String currency = payPalParameters.getString("currency"); final String description = payPalParameters.getString("description");

PayPalConfiguration config = new PayPalConfiguration().environment(environment).clientId(clientId);

startPayPalService(config);

PayPalPayment thingToBuy = new PayPalPayment( new BigDecimal(price), currency, description, PayPalPayment.PAYMENT_INTENT_SALE);

Intent intent = new Intent(activityContext, PaymentActivity.class) .putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, config) .putExtra(PaymentActivity.EXTRA_PAYMENT, thingToBuy);

currentActivity.startActivityForResult(intent, paymentIntentRequestCode); } }

public class PayPal extends ReactContextBaseJavaModule { @ReactMethod public void paymentRequest( final ReadableMap payPalParameters, final Callback successCallback, final Callback errorCallback ) { final String environment = payPalParameters.getString("environment"); final String clientId = payPalParameters.getString("clientId"); final String price = payPalParameters.getString("price"); final String currency = payPalParameters.getString("currency"); final String description = payPalParameters.getString("description");

PayPalConfiguration config = new PayPalConfiguration().environment(environment).clientId(clientId);

startPayPalService(config);

PayPalPayment thingToBuy = new PayPalPayment( new BigDecimal(price), currency, description, PayPalPayment.PAYMENT_INTENT_SALE);

Intent intent = new Intent(activityContext, PaymentActivity.class) .putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, config) .putExtra(PaymentActivity.EXTRA_PAYMENT, thingToBuy);

currentActivity.startActivityForResult(intent, paymentIntentRequestCode); } }

public class PayPal extends ReactContextBaseJavaModule { @ReactMethod public void paymentRequest( final ReadableMap payPalParameters, final Callback successCallback, final Callback errorCallback ) { final String environment = payPalParameters.getString("environment"); final String clientId = payPalParameters.getString("clientId"); final String price = payPalParameters.getString("price"); final String currency = payPalParameters.getString("currency"); final String description = payPalParameters.getString("description");

PayPalConfiguration config = new PayPalConfiguration().environment(environment).clientId(clientId);

startPayPalService(config);

PayPalPayment thingToBuy = new PayPalPayment( new BigDecimal(price), currency, description, PayPalPayment.PAYMENT_INTENT_SALE);

Intent intent = new Intent(activityContext, PaymentActivity.class) .putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, config) .putExtra(PaymentActivity.EXTRA_PAYMENT, thingToBuy);

currentActivity.startActivityForResult(intent, paymentIntentRequestCode); } }

PLATAFORMAS

PLATAFORMAS

PLATAFORMAS

=

PLATAFORMAS

=

PLATAFORMAS

=

PLATAFORMASconst Loader = Platform.select({ ios: () => require('LoaderIOS'), android: () => require('LoaderAndroid'), })()

render () { ... <Loader /> ... }

PLATAFORMAS

import Loader from './Loader'

render () { ... <Loader /> ... }

- Loader.ios.js- Loader.android.js

REACT NATIVE TOOLS

REACT NATIVE TOOLS

REACT NATIVE TOOLS

Não precisa compilar

Desenvolvimento dinâmico

Monitor de performance

REACT NATIVE TOOLS

$ react-native logs-ios$ react-native logs-android

REACT NATIVE TOOLS

$ react-native logs-ios$ react-native logs-android

Debug on Chrome

CODE PUSH

CODE PUSH

CODE PUSH

CODE PUSH

npm i —save react-native-code-push@latest

CODE PUSHnpm i —save react-native-code-push@latest

import codePush from ‘react-native-code-push'

...

componentDidMount() { codePush.sync()

}

CODE PUSHnpm i —save react-native-code-push@latest

import codePush from ‘react-native-code-push'

...

componentDidMount() { codePush.sync()

}

code-push release-react SampleApp ios

CODE PUSH

code-push release-react SampleApp

-- rollout 25%

-- targetBinaryVersion “~1.1.0”

CODE PUSH

code-push rollback

RNPM

RNPM

RNPM

RNPM

RNPM

RNPM

RNPM

npm i rnpm -g

RNPMnpm i rnpm -g

npm i react-native-module --savernpm link react-native-module

RNPMnpm i rnpm -g

rnpm install react-native-module

BOAS PRÁTICAS

BOAS PRÁTICAS

ESTRUTURA DO SEU PROJETO

FLUXO DE DADOS

TESTANDO SEUS COMPONENTES

FLUXO DE DADOS

COMPONENT

FLUXO DE DADOSCOMPONENT

API

FLUXO DE DADOSCOMPONENT

API

class SampleComponent extends Component { ... componentDidMount() {

fetch(‘http://api.com/data‘).then((res) => { this.setState({ data: res })

}) } ...

}

FLUXO DE DADOSCOMPONENT

API

COMPONENT

API

COMPONENT

API

COMPONENT

API

COMPONENT

API

FLUXO DE DADOSCOMPONENT

API

COMPONENT

API

COMPONENT

API

COMPONENT

API

COMPONENT

API

FLUXO DE DADOS

FLUXO DE DADOS

REDUX

COMPONENT

API

ACTION CREATORS

REDUX

COMPONENTAPI

ACTION CREATORS REDUCERS

REDUX

COMPONENTAPI

ACTION CREATORS

STORE

REDUCERS

REDUX

COMPONENTAPI

ACTION CREATORS

STORE

REDUCERS

REDUX

COMPONENTAPI

ACTION CREATORS

componentDidMounted

STORE

REDUCERS

REDUX

COMPONENTAPI

ACTION CREATORS

componentDidMounted

fetchData STORE

REDUCERS

REDUX

COMPONENTAPI

ACTION CREATORS

componentDidMounted

fetchDataHTTP STORE

REDUCERS

REDUX

COMPONENTAPI

ACTION CREATORS

componentDidMounted

fetchDataHTTP JSON STORE

REDUCERS

REDUX

COMPONENTAPI

ACTION CREATORS

STORE

REDUCERS

componentDidMounted

fetchDataHTTP JSON

Data

REDUX

COMPONENTAPI

ACTION CREATORS

STORE

REDUCERS

componentDidMounted

fetchDataHTTP JSON

Data

New State

REDUX

COMPONENTAPI

ACTION CREATORS

STORE

REDUCERS

componentDidMounted

fetchDataHTTP JSON

Data

New State

State

BOAS PRÁTICAS

ESTRUTURA DO SEU PROJETO

FLUXO DE DADOS

TESTANDO SEUS COMPONENTES

TESTANDO SEUS COMPONENTES

TESTANDO SEUS COMPONENTES

TESTANDO SEUS COMPONENTES

TESTANDO SEUS COMPONENTES

COMPONENTACTION CREATORS STOREREDUCERS

TESTANDO SEUS COMPONENTES

COMPONENTACTION CREATORS STOREREDUCERS

TESTANDO SEUS COMPONENTES

COMPONENTACTION CREATORS STOREREDUCERS

TESTANDO SEUS COMPONENTES

COMPONENTACTION CREATORS REDUCERS

TESTANDO SEUS COMPONENTES

ACTION CREATORS

describe('actions', () => { it('should create an action to load items', () => {

// given const loading = true const expectedAction = {

type: 'START_LOADER', loading: loading

} // when let action = actions.loadItems() // then expect(action).toEqual(expectedAction)

} })

TESTANDO SEUS COMPONENTES

COMPONENTACTION CREATORS REDUCERS

REDUCERS

TESTANDO SEUS COMPONENTESdescribe('items reducer', () => {

it('should handle START_LOADER', () => { // given const initialState = { loading: false, items: [] } const expectedState = {

loading: true, items: []

} const action = {

type: 'START_LOADER', loading: true

} // when let state = reducer(initialState, action) // then expect(state).toEqual(expectedState)

} })

TESTANDO SEUS COMPONENTES

COMPONENTACTION CREATORS REDUCERS

COMPONENT

TESTANDO SEUS COMPONENTESclass ItemList extends Component {

constructor(props) { super(props)

}

_handleLoader() { if (this.props.loading) {

return <Loader /> }

}

render() { let loader = this._handleLoader() return (

<View> {loader}

</View> )

} }

COMPONENT

TESTANDO SEUS COMPONENTES

describe(‘ItemList Component', () => { it('should render a view without loader', () => {

// given const props = { loading: false, } // when let renderer = TestUtils.createRenderer() renderer.render(<ItemList {...props} />) let output = renderer.getRenderOutput() // then expect(output.type).toBe(View) expect(output.props.children).toEqual(undefined)

} })

TESTANDO SEUS COMPONENTES

COMPONENTACTION CREATORS REDUCERS

TESTANDO SEUS COMPONENTES

COMPONENTACTION CREATORS REDUCERS

SERVER

TESTANDO SEUS COMPONENTES

COMPONENTACTION CREATORS REDUCERS

SERVER

BOAS PRÁTICAS

ESTRUTURA DO SEU PROJETO

FLUXO DE DADOS

TESTANDO SEUS COMPONENTES

ESTRUTURA DO SEU PROJETO

your-project/ android/ ios/ - index.android.js- index.ios.js

ESTRUTURA DO SEU PROJETOyour-project/

android/ ios/ src/ - index.android.js- index.ios.js

ESTRUTURA DO SEU PROJETOyour-project/

android/ ios/ src/

actions/ components/ containers/ reducers/ store/

- index.android.js- index.ios.js

ESTRUTURA DO SEU PROJETO

src/ actions/

- Posts.js - Posts.spec.js

components/ containers/ reducers/ store/

ESTRUTURA DO SEU PROJETOsrc/

actions/ components/

- Loader.js - Loader.spec.js - Post.js - Post.spec.js

containers/ reducers/ store/

ESTRUTURA DO SEU PROJETOsrc/

actions/ components/

base/ - Loader.js - Loader.spec.js

post/ - Post.js - Post.spec.js - PostActions.js - PostActions.spec.js account/ - AccountSettings.js - AccountSettings.spec.js

containers/ reducers/ store/

ESTRUTURA DO SEU PROJETOsrc/

actions/ components/ containers/ - Root.js - Root.spec.js - Timeline.js - Timeline.spec.js - Account.js - Account.spec.js reducers/ store/

ESTRUTURA DO SEU PROJETOsrc/

actions/ components/ containers/ reducers/ - Root.js - Root.spec.js - Posts.js - Posts.spec.js - Account.js - Account.spec.js store/

ESTRUTURA DO SEU PROJETO

src/ actions/ components/ containers/ reducers/ store/ - ConfigureStore.js

SAMPLE APP

SAMPLE APP

https://github.com/Vizir/ReactNativeWorkshop

Obrigadochagas@vizir.com.br

github.com/chagasaway

Recommended