Aplicações Client-Side Híbridas com React.JS e React Native
Caio Almeida
JSday @ Recife, 16 de Dezembro de 2017
@caiosba
http://ca.ios.ba
- Bacharel e Mestre em Ciência da Computação (UFBA)
- Engenheiro de Software do Meedan (São Francisco/Califórnia/EUA)
- Colaborador em projetos JavaScript, Ruby On Rails, PHP
O que é React.JS?
- Desenvolvido pelo Facebook
- Biblioteca para a camada de visualização (e não um framework)
- React.js sozinho não irá criar uma aplicação web
REACT.JS NÃO POSSUI...
- Controllers
- Directives
- Templates
- Global Event Listeners
- Models
- (...)
APENAS
COMPONENTES
REGRA #1:
TUDO EM REACT.JS É UM COMPONENTE
ShoppingCartComponent
ShoppingCartComponent
CartListComponent
ShoppingCartComponent
CartListComponent
CartItemComponent
Separação de Concerns
x
Separação de Componentes
Componentes podem ser:
- Compostos
- Reutilizados
- Mantidos
- Testados
- Caso eles sejam auto-contidos
import React, { Component, PropTypes } from 'react';
class Embedly extends Component {
render() {
return (
<div className="embed">
<a id="embedly" href={this.props.url}></a>
</div>
);
}
}
export default Embedly;
Embedly.js
JSX
- Linguagem de marcação parecida com HTML
- Descrição declarativa da interface
- Combina a facilidade dos templates com o poder do JavaScript
- Pré-processador traduz JSX para JavaScript plano
REGRA #2:
REACT.JS
REDESENHA TUDO
EM QUALQUER ATUALIZAÇÃO
PARECE CUSTOSO? Mas é rápido!
VIRTUAL DOM
- Cria uma descrição leve da interface do componente
- Calcula as diferenças entre esta versão e a anterior
- Computa o conjunto mínimo de alterações a serem aplicadas ao DOM
- Executa em lote todas as alterações
Regra #3:
Única fonte de dados
props
Imutáveis
state
Mutável
Relay: GraphQL Queries (leitura) e
Mutations (escrita (create, update, delete))
Ciclo
de Vida
import React, { Component, PropTypes } from 'react';
class Example extends Component {
componentWillMount() {
window.alert('Your component is loading');
}
componentWillReceiveProps: function(nextProps) {
this.setState({
increasing: nextProps.count > this.props.count
});
}
componentDidMount() {
window.alert('Your component is ready');
}
render() {
return (<p>Mounted</p>)
}
}
export default Example;
React Native
- Uma biblioteca que converte JSX para:
- iOS Cocoa
- Android UI
- Aplicações com performance similar a aplicação nativa
- Extensível
- É possível reaproveitar componentes
- Código portável para Android e iOS
React Native
- Performance
- Sua equipe já utiliza React.JS e possui componentes bem auto-contidos
- Aplicações mais complexas
Ionic et al.
- Aplicações mais simples
- Prazo x Curva de Aprendizado
- Mesma versão da aplicação para web e para dispositivos móveis?
class Tags extends Component {
render() {
return (
<ul className="tags-list">
{props.tags.map(function(tag) {
return (
<Tag tag={tag}>
);
})}
</ul>
);
}
}
Componente React
React.js
DOM
React Native
Android
iOS
React Native Modules
- Alguns implementados por padrão
- Outros implementados pela comunidade
- Documentação para quem quiser criar seus próprios
React.JS + React Native = Keefer
https://github.com/meedan/generator-keefer
Um código, diferentes plataformas
- Yeoman Generator
- Gera um esqueleto de aplicação React / React Native
- Recebe uma URL como parâmetro
- Tema via SASS
- Documentação
- Abstração de plataforma: apenas o componente pai varia entre plataformas
- Docker
- GraphQL / Relay
- Testes automatizados
$ git clone 'https://github.com
/meedan/generator-keefer.git'
$ cd generator-keefer
$ cp config.yml.example config.yml
$ npm install -g yo
$ npm link
$ yo keefer
Plataforma: Web
URL via parâmetro
$ PLATFORM=web npm run build
Plataforma: Extensão para Navegador
URL via link clicado ou endereço da aba atual
$ PLATFORM=chrome npm run build
Plataforma: Móvel
URL via menu de compartilhamento
$ PLATFORM=android npm run build
===
- State
- Props
- Relay: GraphQL Queries
- Relay: Mutations
!==
- Styles
- Requisições Web
- Sessão (cookies)
- Input
- Local Storage
- DOM
- Internacionalização
React.JS x React Native
1/7: Estilos
React Native Style
- Implementação própria de estilo
- Apenas dois tipos de layout: flexbox ou absoluto
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
<View style={styles.container}>
</View>
1/7: Estilos
https://github.com/caiosba/react-native-css
description {
margin-bottom: 20px;
font-size: 18px;
text-align: center;
color: #656656;
}
container {
padding: 30px;
margin-top: 65px;
align-items: center;
display: block;
}
// style.js
module.exports = require('react-native').StyleSheet.create(
{
"description": {
"marginBottom":20,
"fontSize":18,
"textAlign":"center",
"color":"#656656"
},
"container":{
"padding":30,
"marginTop":65,
"alignItems":"center"
}
}
);
1/7: Estilos
2/7: Requisições Web
superagent
fetch
superagent.get(url).withCredentials().end(
(err, response) => {...}
);
fetch(url, { headers: { credentials: 'include' } }).then(
response => { ... }
);
3/7: Sessão (cookies)
1) Autenticação via API (fetch) e armazenamento de token
2) Autenticação via React Native Cookie Manager (https://github.com/joeferraro/react-native-cookies)
import CookieManager from 'react-native-cookies';
CookieManager.setFromResponse('http://example.com',
'user_session=abcdefg; path=/; secure; HttpOnly')
.then((res) => {
callback(res);
});
3/7: Sessão (cookies)
3) Autenticação via WebView + postMessage
onMessage(event) {
const { data } = event.nativeEvent;
if (data) {
this.setState({ cookie: data });
}
}
render() {
return (
<WebView
source={{ uri: this.state.url }}
onMessage={this.onMessage.bind(this)}
injectedJavaScript="window.postMessage(document.cookie)"
/>
);
}
https://www.npmjs.com/package/react-native-share-menu
Módulo React Native que adiciona
sua aplicação ao menu "compartilhar" do aparelho e recebe URLs a partir de outros aplicativos
4/7: User Input
5/7: Local Storage
// Web
window.localStorage.setItem(key, value);
// Browser Extension
chrome.storage.sync.set({ key: value})
// Mobile
await AsyncStorage.setItem(key, value);
Implementar uma única função que abstraia para as diferentes plataformas
6/7: Componentes DOM
<!-- Web / Browser Extension -->
<div>
<button onClick={this.send.bind(this)}>Send</button>
</div>
<!-- React Native -->
<View>
<Button onPress={this.send.bind(this)} title="Send" />
</View>
https://github.com/necolas/react-native-web
Permite escrever os componentes em React Native e eles serão convertidos para React DOM
6/7: Componentes DOM
// .babelrc
{
"plugins": [
"react-native-web/babel"
],
"presets": [
"react-native"
]
}
// webpack
module.exports = {
resolve: {
extensions: ['.web.js', '.js',
'.web.jsx', '.jsx'],
alias: {
'react-native': 'react-native-web',
}
}
};
7/7: Internacionalização
<!-- Hybrid -->
<IntlProvider locale={l} messages={msgs} textComponent={Text}>
<FormattedMessage defaultMessage="Original text" id="example" />
</IntlProvider>
<!-- Output: Web and Browser Extension -->
<span>Translated text</span>
<!-- Output: React Native -->
<Text>Translated text</Text>
https://github.com/yahoo/react-intl
Basta definir a propriedade textComponent do componente IntlProvider
7/7: Internacionalização
import { Platform } from 'react-native';
let locale = 'en';
// Mobile
if (this.context.platform === 'mobile') {
// Android
if (Platform.OS === 'android') {
locale = NativeModules.I18nManager.localeIdentifier;
}
// iOS
else {
locale = NativeModules.SettingsManager.settings.AppleLocale;
}
}
// Web and Browser Extension
else {
locale = navigator.languages || navigator.language || navigator.userLanguage;
}
Identificando o idioma atual:
Caso de Uso: Check Mark
https://github.com/meedan/check-mark
Obrigado!
htt//ca.ios.ba
slides.com/caiosba/jsdayrecife2017
Aplicações client-side híbridas com React.js e React Native
By Caio Sacramento
Aplicações client-side híbridas com React.js e React Native
O objetivo desta palestra é mostrar como implementar aplicações JavaScript utilizando React.js e React Native que possam se apresentar como extensões de navegador, aplicações móveis ou aplicações web convencionais. Mais em http://rec.jsday.com.br/speakers/.
- 970