
A tarefa de comparar estruturas é uma tarefa muito ingrata, as preferências dos desenvolvedores são diferentes, as tecnologias mudam muito rapidamente. Rápido demais. Este artigo ficará obsoleto mesmo antes de clicar no botão publicar.
Houve tentativas de comparar, por exemplo, cerca de cinco anos atrás, os caras (Colin Eberhardt e Chris Price) inspiraram vários desenvolvedores a fazer um pedido de busca de imóveis de acordo com o TK claramente compilado. A ideia é legal, até participamos e fizemos uma versão desse aplicativo no
DevExtreme . Mas em termos de apoio, esse projeto é um inferno e agora o projeto
Property Cross representa uma certa camada histórica que causa nostalgia e sentimentos calorosos, mas dificilmente é útil.
Se você pegar apenas o mundo js, isto é, um projeto de
PVC bastante animado que compara apenas a parte js, sem empacotar em um aplicativo móvel, desktop ou qualquer outro aplicativo. O projeto é animado e apoiado. Provavelmente, ainda existem exemplos muito interessantes que não notamos no Google quando estávamos preparando o artigo, mas não ficaremos chateados com isso.
Nosso experimento é menos ambicioso e mostra apenas a seção atual de tecnologias, mesmo uma pequena parte dela. Aqui está um link para o
primeiro e o
segundo artigo do experimento.
Leitura adicional é o terceiro artigo sobre como fazer uma aplicação no React Native de acordo com o TK. É muito semelhante a centenas, e talvez milhares, de outras recontagens de documentação sobre como fazer um aplicativo no React Native. Caro leitor, avisei, minha consciência está limpa.
Lembre-se de TK
Em geral, ele pode ser totalmente visualizado no primeiro artigo. Mas vou adicionar uma imagem do que deve resultar no final. Existem poucas fotos.

Uma pitada de equipamento. O que é o React Native?
O React Native é uma estrutura para criar aplicativos móveis de plataforma cruzada a partir do Facebook. Como no React "regular" para a Web, o aplicativo de interface do usuário é montado a partir de tijolos - componentes que respondem a alterações em seu estado (estado) e propriedades passadas a eles (adereços), mas, diferentemente da Web, são renderizados em controles nativos.
Idealmente, são utilizados os princípios de imunidade e funções puras, o que garante simplicidade e isolamento dos testes. E aqui vale a pena notar que o React em si é muito simples, e essa simplicidade entra na parte móvel.
Complementos adicionais nos códigos nativo e JS suavizam a diferença entre plataformas, quando possível. De fato, o React Native fornece alguma unificação das propriedades do componente em cada sistema operacional.
Por exemplo, ScrollView e HorizontalScrollView são dois componentes diferentes no Android. E no iOS UIScrollView, que suporta rolagem horizontal e vertical. E no React Native, usaremos o seguinte código de plataforma cruzada:
<ScrollView horizontal={true}/>
Com uma abordagem competente, obtemos um aplicativo nativo "honesto" que roda em iOS e Android.
Em um mundo ideal, ao desenvolver no React Native, você não precisa escrever em Java ou Objective-C. Mas existe essa oportunidade quando você precisa implementar um componente que vai além dos recursos do React Native.
Os desenvolvedores do Airbnb brincaram muito com isso, e podemos ver muitas implementações dignas na comunidade reagir que estavam anteriormente em seu repositório. Por exemplo,
Lottie é uma biblioteca para importar animações do Adobe After Effects, ou
mapas de plataforma cruzada .
O código JS no aplicativo é executado no mecanismo
JavaScriptCore . A comunicação entre código nativo e JS é feita usando uma ponte assíncrona (ponte), que permite transferir propriedades (props), acionar eventos (eventos) e retornos de chamada.

Imagem tirada da excelente documentação
React Made Native Easy . (Recomendo a leitura.)
Durante o processo de construção, o novo babel à moda é usado para converter o código JS; isso permite que você use a nova sintaxe do ES6, além de alguns recursos do ES8 (por exemplo, async-waitit). Se você, meu caro leitor, é desenvolvedor js, entende como é bom quando existe um operador de spread e como é ruim quando não é.
Para o layout da página, é usada a tecnologia flexbox, implementada pelo mecanismo de ioga multiplataforma. Tem diferenças em relação à caixa flexível do navegador, mas são insignificantes e estão principalmente relacionadas a padrões. Obviamente, existem nuances, mas você terá sorte e tudo ficará de acordo com a documentação.
Preparando e implantando a pilha. Terminal de tubo
Para trabalhar com o RN, precisamos do
Node.js e do gerenciador de pacotes npm, que vem incluído. Não é necessário, mas é muito desejável instalar o aplicativo
Expo no seu dispositivo. Isso permitirá que você inicie nosso projeto em seu telefone, além de criar e executar um aplicativo iOS quando você não tiver o macOS em mãos.
Vamos criar um novo aplicativo. Para fazer isso, use o pacote
create-react-native-app .
No terminal, execute:
npm install -g create-react-native-app create-react-native-app notes cd notes npm run start
Digitalize o código QR usando a Expo ou insira um link no terminal, ou mesmo envie o link para o seu telefone, diretamente do terminal.
Geralmente, desconfio que os desenvolvedores do cli para reagir nativos tenham um velho de cabelos grisalhos que encontrou brinquedos roguelike sem interface do usuário quando há apenas um terminal e, em vez de uma placa de vídeo topo de linha, apenas sua imaginação.

Mas nós, entretanto, acabamos de criar e lançar o aplicativo "Hello World".
E todo o "Olá Mundo" -a não é suficiente. Analisar TK
De acordo com a declaração de trabalho, a estrutura de dados do aplicativo será
Note: { userName: string, avatar: string, editTime: string, text: string } Project: { name: string, notes: Array<Note> } Projects: Array<Project>
Para trabalhar com esses dados, eu usaria uma solução muito elegante com base no CQRS. Isso permitiria preservar a integridade dos dados, fornecendo alta velocidade de leitura com a capacidade de reorganizar as projeções, além de uma rápida implantação na nuvem com um único comando. Como o
Resolve , desenvolvido por nossos colegas.
Mas eu não aceito, temos um experimento simples, sem back-end. E, por simplicidade, usarei a arquitetura de
fluxo , em particular sua implementação -
redux . Os dados do estado do aplicativo chegam aos componentes como acessórios. Os componentes podem chamar ações para atualizar dados.
O aplicativo terá 3 telas, todas de acordo com o ToR:
- lista de projetos - Projetos,
- página detalhada do projeto com uma lista de notas - Projeto,
- página de nota detalhada - Nota
Para a navegação entre telas, usarei a biblioteca de
navegação de reação padrão. Os números próximos ao gráfico na página da biblioteca mostram quantas vezes ele é baixado por semana. Agora existem cerca de 100 mil por semana. É bom que eu não tenha sido o único que escolheu essa biblioteca para navegação. E sim, você pode ver os dígitos de outros pacotes npm que indiquei neste artigo para entender aproximadamente o número de usuários dessa tecnologia em um determinado momento.
Crie uma aplicação
Para o React Native, o componente App do arquivo App.js é o ponto de entrada para o aplicativo.
export default class App extends Component { render() { return ( <Provider store={store}> <Navigator /> </Provider> ) } }
O armazenamento com dados e o estado do aplicativo é conectado pelo componente Provider da biblioteca react-redux. Isso fornece o encaminhamento de dados para componentes aninhados.
Crie um navegador para transições entre telas no aplicativo. Ele reflete claramente a estrutura do aplicativo, declarada no experimento, e desenha transições animadas entre telas para cada plataforma.
const Navigator = createStackNavigator({ Projects: { screen: Projects }, Project: { screen: Project }, Note: { screen: Note } })
As telas do navegador são componentes - contêineres. Eles obtêm dados do estado do aplicativo.
Lista de Projetos - Projetos
Na tela com uma lista de projetos, haverá uma lista e um botão para adicionar um projeto - no cabeçalho da janela à direita. Criaremos um novo projeto na tela Projeto.
Para a navegação, usamos o objeto de navegação, que passou para os componentes do componente pai - o navegador.
export class Projects extends PureComponent { static navigationOptions = ({ navigation }) => ({ headerRight: ( <AddButton onPress={() => navigation.navigate('Project')} /> ) }) navigateProject = project => { this.props.navigation.navigate('Project', { projectId: project.id, name: project.name }) } render() { return ( <ProjectList projects={this.props.projects} onPressProject={this.navigateProject} /> ) } }
Para exibir a lista de projetos, usaremos o FlatList - uma lista de plataforma cruzada com virtualização:
export class ProjectList extends PureComponent { static propTypes = { projects: ProjectsType, onPressProject: PropTypes.func } renderItem = ({ item }) => ( <ProjectListItem project={item} onPressProject={this.props.onPressProject} /> ) render() { return ( <FlatList data={this.props.projects} keyExtractor={item => item.id} renderItem={this.renderItem} /> ) } }
Para cada elemento, definimos uma chave exclusiva - aqui temos o ID do elemento. Isso é necessário para que a reação possa distinguir entre os elementos da lista e atualizar apenas os que foram alterados.
Adicione um componente ao item da lista.
export class ProjectListItem extends PureComponent { static propTypes = { project: ProjectType, onPressProject: PropTypes.func } onPressProject = () => { const { project, onPressProject } = this.props onPressProject(project) } render() { return ( <TouchableOpacity onPress={this.onPressProject}> <View style={styles.project}> <Text style={styles.name}>{this.props.project.name}</Text> </View> </TouchableOpacity> ) } }
TouchableOpactity - um wrapper que responde a cliques. Quando clicado, o componente aninhado se torna mais transparente.
View - análogo de div para web - componente básico de marcação.
Texto - um contêiner para texto.
Adicione estilos:
const styles = StyleSheet.create({ project: { paddingVertical: 30, paddingHorizontal: 15, backgroundColor: 'white', borderBottomWidth: StyleSheet.hairlineWidth, borderColor: 'gray' }, name: { fontSize: 16 } })
A sintaxe do estilo é semelhante a css, a principal diferença é que você pode estilizar apenas o componente em si (por exemplo, não é possível definir o tamanho da fonte para todo o aplicativo, apenas para um componente de texto específico)

Página detalhada do projeto com uma lista de notas - Projeto
Da mesma forma, crie uma página detalhada. As diferenças estão apenas na presença de um título no navegador e de entrada adicional. No navegador, defina o título - o nome do projeto. Se o ID do projeto não for especificado, ofereceremos para inserir o nome do projeto e criar um novo.
export class Project extends PureComponent { static navigationOptions = ({ navigation }) => { const projectId = navigation.getParam('projectId') return { title: navigation.getParam('name', ''), headerRight: ( <AddButton onPress={() => navigation.navigate('Note', { projectId })} /> ) } } removeNote = noteId => { const { projectId, removeNote } = this.props removeNote(projectId, noteId) } navigateNote = noteId => { const { projectId, navigation } = this.props navigation.navigate('Note', { noteId, projectId }) } createProject = name => { const newProjectId = shortid.generate() this.props.navigation.setParams({ projectId: newProjectId, name }) this.props.addProject(newProjectId, name) } render() { const { projectId, project } = this.props if (!projectId) { return ( <ProjectNameInput onSubmitEditing={this.createProject} /> ) } return ( <NoteList notes={project.notes} onNavigateNote={this.navigateNote} onRemoveNote={this.removeNote} /> ) } }
A página do projeto é uma lista de notas. De acordo com o ToR para cada nota, há um menu de contexto com edição e exclusão. Você também pode excluir a nota com um furto. Há uma lista separada no React Native, com a capacidade de deslizar - SwipeableFlatList.
<SwipeableFlatList data={this.props.notes} bounceFirstRowOnMount={false} keyExtractor={item => item.id} maxSwipeDistance={MAX_SWIPE_DISTANCE} renderQuickActions={this.renderQuickActions} renderItem={this.renderItem} />
Ao excluir uma nota, solicitaremos confirmação, e chamaremos o alerta padrão do sistema
onRemoveNote = noteId => { Alert.alert( 'Remove Note', 'Do you want to remove note ?', [ { text: 'Cancel', onPress: () => {}}, { text: 'Remove', onPress: () => this.props.onRemoveNote(noteId) } ] ) }

Há um ponto interessante para o menu de contexto. Ao contrário do alerta, sua implementação no RN para Android e iOS é diferente.
Para android, use o menu pop-up
showPopupMenu = () => { const button = findNodeHandle(this._buttonRef) UIManager.showPopupMenu( button, [ 'Edit', 'Delete' ], e => console.error(e), (e, i) => this.onPressMenu(i) ) }
Para iOS - actionSheet
showActionSheet = () => { ActionSheetIOS.showActionSheetWithOptions({ options: [ 'Edit', 'Delete', 'Cancel' ], destructiveButtonIndex: 1, cancelButtonIndex: 2 }, this.onPressMenu ) }
Existem várias maneiras de dividir o código específico da plataforma. Usaremos o objeto Platform.
onOpenMenu = Platform.select({ android: this.showPopupMenu, ios: this.showActionSheet })

Página Nota detalhada - Nota
A página de anotações também é bastante primitiva. Mas, diferentemente dos anteriores, usamos state para armazenar resultados intermediários de entrada do usuário.
export class Note extends PureComponent { static navigationOptions = ({ navigation }) => ({ headerRight: ( <SaveButton onPress={navigation.getParam('onSaveNote')} /> ) }) state = { noteText: '' } componentDidMount() { this.props.navigation.setParams({ onSaveNote: this.onSaveNote }) } onSaveNote = () => { Keyboard.dismiss() const { projectId, noteId, note, navigation, addNote, editNote } = this.props const { noteText } = this.state if (!noteId) { const newNoteId = shortId.generate() navigation.setParams({ noteId: newNoteId }) addNote(projectId, newNoteId, noteText) } else if (noteText && noteText !== note.text) { editNote(projectId, noteId, noteText) } } onChangeNote = noteText => { this.setState({ noteText }) } render() { const initialTextValue = this.props.note ? this.props.note.text : '' const noteText = this.state.noteText || initialTextValue return ( <NoteDetail noteText={noteText} onChangeNoteText={this.onChangeNote} /> ) } }
A tela detalhada da nota - o componente "bobo" clássico - relata para cima a alteração do texto e mostra o texto que o pai passa para ela
export class NoteDetail extends PureComponent { static propTypes = { noteText: PropTypes.string, onChangeNoteText: PropTypes.func } render() { const { noteText, onChangeNoteText } = this.props return ( <View style={styles.note}> <TextInput multiline style={styles.noteText} value={noteText} placeholder="Type note text here ..." underlineColorAndroid="transparent" onChangeText={onChangeNoteText} /> </View> ) } }

No total, recebemos o aplicativo como no TK. O experimento está concluído. O código do aplicativo pode ser visualizado no
repositório geral
Total, prós e contras do React Native
Prós:
O React Native é familiar e compreensível para os desenvolvedores familiarizados com o React e a estrutura Node.js e npm. É possível usar todas as abordagens e bibliotecas, como no React usual.
Um grande número de pacotes js do npm. Provavelmente, a maioria das tarefas padrão já foi resolvida e, possivelmente, sob uma licença MIT.
Grande comunidade. Tanto os desenvolvedores individuais quanto as grandes empresas usaram o RN para o desenvolvimento e continuam a usá-lo.
Muitos conjuntos prontos de componentes de interface do usuário, como
NativeBase ,
React Native Elements , bibliotecas de grandes empresas como Facebook, Airbnb, Wix.com.
Kit de ferramentas claro para o desenvolvimento conveniente de aplicativos, do Hello World ao
Instagram .
Contras:
O aplicativo inicia mais lentamente que o nativo e há algumas dificuldades de depuração. O código JS dentro e sem o depurador é executado em diferentes mecanismos. O Airbnb escreveu muito bem sobre esse problema em uma
série de artigos sobre por que eles abandonaram o React Native em desenvolvimento.
Como o kit de ferramentas consiste em muitos pacotes desenvolvidos separadamente, existe a possibilidade de conflito de versão e interrupção.
Nem tudo pode ser feito sem o código nativo. E quando você faz alterações no código nativo, perde a capacidade de usar o Expo e se força a criar o aplicativo usando ferramentas de desenvolvimento nativas padrão.
Muito obrigado a
Mirimon e
HeaTTheatR por
me convidarem a participar desse experimento. Foi emocionante. Por fim, adicione um voto.