REACT NATIVE
REACT NATIVE Workshop
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…
REACT COMPONENTES
REACT COMPONENTES TUDO PODE SER JAVASCRIPT
REACT VIRTUAL DOM COMPONENTES TUDO PODE SER JAVASCRIPT
COMPONENTES APP
COMPONENTES HEADER TABS CARD CARD
COMPONENTES HEADER TABS CARD CARD IMAGE USER AVATAR CARD TEXT CARD IMAGE USER AVATAR CARD TEXT
COMPONENTES HEADER TABS CARD CARD IMAGE USER AVATAR CARD TEXT CARD IMAGE USER AVATAR CARD TEXT HEADER TABS ACCOUNT INFO USER AVATAR ACCOUNT SETTINGS
CARD TEXT CARD IMAGE USER AVATAR COMPONENTES
CARD TEXT CARD IMAGE USER 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 IMAGE USER AVATAR CARD TEXT COMPONENTES
COMPONENTES componentWillMount
COMPONENTES componentWillMount componentDidMount
COMPONENTES componentWillMount componentDidMount componentWillReceiveProps
COMPONENTES componentWillMount componentDidMount componentWillReceiveProps shouldComponentUpdate
COMPONENTES componentWillMount componentDidMount componentWillReceiveProps shouldComponentUpdate componentWillUpdate
COMPONENTES componentWillMount componentDidMount componentWillReceiveProps shouldComponentUpdate componentWillUpdate componentDidUpdate
COMPONENTES componentWillMount componentDidMount componentWillReceiveProps shouldComponentUpdate componentWillUpdate componentDidUpdate componentWillUnmount
COMPONENTES componentWillMount componentDidMount componentWillReceiveProps shouldComponentUpdate componentWillUpdate componentDidUpdate componentWillUnmount Props
COMPONENTES componentWillMount 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} /> JSX let 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 DOM HTML DOM JAVASCRIPT
VIRTUAL DOM HTML DOM JAVASCRIPT VIRTUAL DOM
VIRTUAL DOM VIRTUAL DOM ANDROID DOM iOS DOM HTML DOM
VIRTUAL DOM ANDROID DOM iOS DOM HTML DOM SONY DOM SAMSUNG DOM WINDOWS DOM BRASTEMP DOM LG DOM PHILIPS DOM
REACT NATIVE
COMPONENTES View Image Text Activity Indicator Modal Navigator Refresh Control ScrollView StatusBar Switch ListView TextInput WebView MapView ProgressBar Android …
APIs Alert Animated AppState BackAndroid CameraRoll Clipboard DatePicker Android Dimensions Geolocation Linking NetInfo ToastAndroid PixelRatio PushNotification IOS Vibration +++
COMUNIDADE
COMUNIDADE
COMUNIDADE
BIBLIOTECAS NATIVAS
BIBLIOTECAS NATIVAS BIBLIOTECA NATIVA REACT NATIVE
BIBLIOTECAS NATIVAS BIBLIOTECA NATIVA REACT NATIVE
BIBLIOTECAS NATIVAS BIBLIOTECA NATIVA REACT NATIVE
BIBLIOTECAS NATIVAS BIBLIOTECA 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 =
PLATAFORMAS const 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 PUSH npm i —save react-native-code-push@latest import codePush from ‘react-native-code-push' ... componentDidMount() { codePush.sync() }
CODE PUSH npm 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
RNPM npm i rnpm -g npm i react-native-module --save
 rnpm link react-native-module
RNPM npm 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 DADOS COMPONENT API
FLUXO DE DADOS COMPONENT API class SampleComponent extends Component { ... componentDidMount() { fetch(‘http://api.com/data‘).then((res) => { this.setState({ data: res }) }) } ... }
FLUXO DE DADOS COMPONENT API COMPONENT API COMPONENT API COMPONENT API COMPONENT API
FLUXO DE DADOS COMPONENT 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 COMPONENT ACTION CREATORS STOREREDUCERS
TESTANDO SEUS COMPONENTES COMPONENT ACTION CREATORS STOREREDUCERS
TESTANDO SEUS COMPONENTES COMPONENT ACTION CREATORS STOREREDUCERS
TESTANDO SEUS COMPONENTES COMPONENT ACTION 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 COMPONENT ACTION CREATORS REDUCERS
REDUCERS TESTANDO SEUS COMPONENTES describe('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 COMPONENT ACTION CREATORS REDUCERS
COMPONENT TESTANDO SEUS COMPONENTES class 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 COMPONENT ACTION CREATORS REDUCERS
TESTANDO SEUS COMPONENTES COMPONENT ACTION CREATORS REDUCERS SERVER
TESTANDO SEUS COMPONENTES COMPONENT ACTION 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 PROJETO your-project/ android/ ios/ src/ - index.android.js
 - index.ios.js
ESTRUTURA DO SEU PROJETO your-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 PROJETO src/ actions/ components/ - Loader.js - Loader.spec.js - Post.js - Post.spec.js containers/ reducers/ store/
ESTRUTURA DO SEU PROJETO src/ 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 PROJETO src/ actions/ components/ containers/ - Root.js - Root.spec.js - Timeline.js - Timeline.spec.js - Account.js - Account.spec.js reducers/ store/
ESTRUTURA DO SEU PROJETO src/ 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
Obrigado chagas@vizir.com.br
 github.com/chagasaway

React Native - Workshop