portaldacalheta.pt
  • Principal
  • Talento Ágil
  • Lucratividade E Eficiência
  • Móvel
  • Estilo De Vida
Web Front-End

Angular vs. React: Qual é o melhor para desenvolvimento Web?



Existem inúmeros artigos por aí debatendo se React ou Angular é a melhor opção para desenvolvimento web. Precisamos de outro?

A razão pela qual escrevi este artigo é porque nenhum dos a artigos já Publicados –Embora contenham grandes ideias– eles vão fundo para um desenvolvedor de front-end prático decidir qual deles pode atender às suas necessidades.



Angular vs. Reagir: Você escolhe a forma da estrutura ou brinca com as livrarias?



Neste artigo, você aprenderá como Angular e React visam resolver problemas de front-end semelhantes, embora com filosofias muito diferentes, e se escolher um ou outro é simplesmente uma questão de preferência pessoal. Para compará-los, vamos construir o mesmo aplicativo duas vezes, uma vez com Angular e novamente com React.



Anúncio Inoportuno da Angular

Dois anos atrás, escrevi um artigo sobre React Ecossystem . Entre outros pontos, o artigo argumenta que a Angular foi vítima de 'morte por anúncio anterior'. Naquela época, a escolha entre o Angular e qualquer outra coisa era fácil para quem não queria que seu projeto funcionasse com uma estrutura desatualizada. O Angular 1 foi descontinuado e o Angular 2 nem estava disponível em alfa.

Em retrospecto, os temores eram mais ou menos justificados. Angular 2 mudou dramaticamente e até passou por uma grande reescrita pouco antes do lançamento final.



Dois anos depois, temos o Angular 4 com a promessa de estabilidade relativa no futuro.

E agora que?



Angular vs. Reaja: Comparando Maçãs e Laranjas

Algumas pessoas dizem que comparar React e Angular é como comparar maçãs com laranjas. Enquanto uma é uma biblioteca que trata de opiniões, a outra é uma estrutura completa.

Claro, a maior parte do React developers eles adicionarão algumas bibliotecas ao React para torná-lo uma estrutura completa. Além disso, o fluxo de trabalho resultante dessa pilha ainda é muito diferente do Angular, portanto, a comparabilidade ainda é limitada.



A maior diferença está na administração estadual. O Angular vem com vinculação de dados incluída, enquanto o React hoje geralmente é ampliado pelo Redux para fornecer fluxo de dados unilateral e trabalhar com dados imutáveis. Essas são abordagens opostas em seu próprio direito, e inúmeras discussões estão começando agora se mutável / união de dados é melhor ou pior do que imutável / unilateral.

Um campo de jogo nivelado

Como o React é notoriamente mais fácil de hackear, decidi, para o propósito desta comparação, construir uma configuração do React que reflita Angular razoavelmente perto para permitir a comparação lado a lado de trechos de código.



Alguns recursos angulares que se destacam, mas não são encontrados no React por padrão são:

Característica Pacote angular Biblioteca React
Vinculação de dados, injeção de dependência (DI) @ angular / core MobX
Propriedades computadas rxjs MobX
Roteamento baseado em componente @ angular / roteador Roteador React v4
Componentes de design de material @ angular / material React Toolbox
CSS com escopo para componentes @ angular / core Módulos CSS
Validações de formulário @ angular / forms FormState
Gerador de projeto @ angular / cli React Scripts TS

Link de dados

A vinculação de dados é indiscutivelmente mais fácil de começar do que a abordagem unilateral. Claro, seria possível ir na direção completamente oposta e usar Restaurado ou mobx-state-tree com React, e ngrx com Angular. Mas isso seria um assunto para outro post.



Propriedades Calculadas

No que diz respeito ao desempenho, os captadores de nível no Angular estão simplesmente fora de questão, pois são chamados em cada processamento. É possível usar BehaviorSubject a partir de RsJS , que realiza o trabalho.

Com o React, é possível usar @computed da MobX, que atinge o mesmo objetivo, com uma API ligeiramente melhor.

Injeção de dependência

A injeção de dependência é um pouco controversa porque vai contra o paradigma React atual de programação funcional e imutabilidade. Acontece que algum tipo de injeção de dependência é quase indispensável em ambientes de vinculação de dados, pois ajuda na dissociação (e, portanto, na simulação e teste) onde não há arquitetura de camada de dados separada.

Mais uma vantagem do DI (suportado pelo Angular) é a capacidade de ter diferentes ciclos de vida de diferentes lojas. A maioria dos paradigmas React atuais usa algum tipo de estado de aplicativo global que mapeia componentes diferentes, mas, pela minha experiência, é muito fácil introduzir erros ao limpar o estado global na desmontagem de componentes.

Ter uma loja construída sobre a montagem de componentes (e perfeitamente disponível para os filhos deste componente) parece ser realmente útil, e o conceito é frequentemente esquecido.

o que é ux ui designer

Fora da caixa no Angular, mas facilmente jogável com MobX também.

Encaminhamento

O roteamento baseado em componentes permite que os componentes gerenciem suas próprias rotas secundárias em vez de ter uma grande configuração de roteador global. Esta abordagem finalmente chegou a react-router na versão 4.

Design material

É sempre bom começar com alguns componentes de última geração, e o material design se tornou uma opção padrão universalmente aceita, mesmo em projetos que não são do Google.

Eu escolhi deliberadamente React Toolbox sobre o recomendado IU de material , uma vez que o material da IU confessa seriamente Problemas de desempenho com seu CSS-in-line, que eles planejam resolver na próxima versão.

Mais distante, PostCSS / cssnext ele foi usado no React Toolbox e está começando a substituir o Sass / LESS de qualquer maneira.

CSS com escopo

As classes CSS são algo como variáveis ​​globais. Existem inúmeras abordagens para organizar CSS para evitar conflitos (incluindo BEM ), mas há uma tendência clara no uso de bibliotecas que auxiliem no processamento de CSS para evitar esses conflitos sem a necessidade de um desenvolvedor a parte dianteira para criar sistemas de nomenclatura CSS elaborados.

Validação de Formulário

As validações de formulário são um recurso não trivial e amplamente utilizado. É bom ter aqueles cobertos por uma biblioteca para evitar a repetição de código e erros.

Gerador de Projeto

Ter um gerador CLI para um projeto é apenas um pouco mais conveniente do que clonar planilhas de caldeira do GitHub.

Mesmo aplicativo, construído duas vezes

Então, vamos criar o mesmo aplicativo no React e no Angular. Nada espetacular, apenas um Shoutboard que permite a qualquer pessoa postar mensagens em uma página comum.

Você pode testar os aplicativos aqui:

  • Shoutboard Angular
  • Shoutboard React

Shoutboard app en Angular vs. en React

Se você quiser ter todo o código-fonte, pode obtê-lo no GitHub:

  • Fonte Shoutboard Angular
  • Fonte do Shoutboard React

Você notará que também usamos o TypeScript para o aplicativo React. Os benefícios da verificação de tipo no TypeScript são óbvios. E agora com um melhor manuseio das importações, async / wait and rest propagation finalmente chegou ao TypeScript 2, saindo de Babel / ES7 / Fluxo na poeira.

Além disso, vamos adicionar Cliente Apollo para ambos porque queremos usar GraphQL. Quer dizer, REST é ótimo, mas depois de uma década ou mais ele envelhece.

Bootstrap e roteamento

Primeiro, vamos dar uma olhada nos pontos de entrada de ambos os aplicativos.

Angular

const appRoutes: Routes = [ { path: 'home', component: HomeComponent }, { path: 'posts', component: PostsComponent }, { path: 'form', component: FormComponent }, { path: '', redirectTo: '/home', pathMatch: 'full' } ] @NgModule({ declarations: [ AppComponent, PostsComponent, HomeComponent, FormComponent, ], imports: [ BrowserModule, RouterModule.forRoot(appRoutes), ApolloModule.forRoot(provideClient), FormsModule, ReactiveFormsModule, HttpModule, BrowserAnimationsModule, MdInputModule, MdSelectModule, MdButtonModule, MdCardModule, MdIconModule ], providers: [ AppService ], bootstrap: [AppComponent] }) @Injectable() export class AppService { username = 'Mr. User' }

Basicamente, todos os componentes que queremos usar no aplicativo precisam ir para as declarações. Todas as livrarias terceirizadas para importações e todas as lojas globais para fornecedores. Os componentes filhos têm acesso a tudo isso, com a oportunidade de adicionar mais coisas locais.

Reagir

const appStore = AppStore.getInstance() const routerStore = RouterStore.getInstance() const rootStores = { appStore, routerStore } ReactDOM.render( , document.getElementById('root') )

O componente é usado para injeção de dependência no MobX. Salve os armazenamentos no contexto para que os componentes do React possam injetá-los posteriormente. Sim, o contexto React pode (indiscutivelmente) ser usado com segurança .

A versão React é um pouco mais curta porque não há declarações de módulo - geralmente é apenas importar e você está pronto para começar. Às vezes, esse tipo de dependência rígida é indesejado (em testes), então, para lojas singleton globais, tive que usar isso GoF padronizar década anterior:

export class AppStore { static instance: AppStore static getInstance() (AppStore.instance = new AppStore()) @observable username = 'Mr. User' }

O roteador da Angular é injetável, portanto, pode ser usado de qualquer lugar, não apenas de componentes. Para conseguir o mesmo na reação, usamos o pacote mobx-react-router e injetamos routerStore.

Resumo: A inicialização de ambos os aplicativos é bastante simples. O React tem a vantagem de ser mais simples, usando apenas importações em vez de módulos, mas, como veremos mais tarde, esses módulos podem ser muito úteis. Fazer semifalls manualmente é um pouco chato. Quanto à sintaxe da instrução de roteamento, JSON vs JSX é apenas uma questão de preferência.

Links e navegação imperativa

Portanto, há dois casos para alterar uma rota. Declarativamente, usando elementos e, imperativamente, chamando a API de roteamento (e, portanto, de localização) diretamente.

Angular

Home Posts {this.props.children}

O React Router também pode definir a classe ativa do link com activeClassName.

Aqui, não podemos fornecer o nome da classe diretamente porque ele foi tornado único pelo compilador do módulo CSS e temos que usar o auxiliar style. Falaremos sobre isso mais tarde.

Como visto acima, o React Router usa o elemento dentro de um elemento. Visto que o elemento simplesmente encapsula e monta o caminho atual, isso significa que os subcaminhos do componente atual são simplesmente this.props.children. Portanto, também é combinável.

export class FormStore { routerStore: RouterStore constructor() { this.routerStore = RouterStore.getInstance() } goBack = () => { this.routerStore.history.push('/posts') } }

O pacote mobx-router-store também permite fácil injeção e navegação.

Resumo: Ambas as abordagens de roteamento são bastante comparáveis. Angular parece ser mais intuitivo, enquanto React Router é um pouco mais fácil de compor.

Injeção de dependência

Separar a camada de dados da camada de apresentação já demonstrou ser benéfico. O que estamos tentando conseguir com o DI é fazer com que os componentes das camadas de dados (aqui chamados de modelo / loja / serviço) sigam o ciclo de vida dos componentes visuais e, portanto, permitir fazer uma ou mais instâncias dos referidos componentes sem tocar no status global . Além disso, deve ser possível misturar e combinar dados com suporte e camadas de exibição.

Os exemplos neste artigo são muito simples, então todas as coisas de DI podem parecer excessivas, mas são úteis conforme o aplicativo cresce.

Angular

@Injectable() export class HomeService { message = 'Welcome to home page' counter = 0 increment() { this.counter++ } }

Portanto, qualquer classe pode ser @inyectable, e suas propriedades e métodos disponibilizados para os componentes.

@Component({ selector: 'app-home', templateUrl: './home.component.html', providers: [ HomeService ] }) export class HomeComponent { constructor( public homeService: HomeService, public appService: AppService, ) { } }

Ao registrar o HomeService a providers do componente, o disponibilizamos exclusivamente para este componente. Não é um meio-bug agora, mas cada instância do componente receberá uma nova cópia, nova na montagem do componente. Isso significa que não há dados desatualizados de uso anterior.

Em contraste, o AppService foi registrado no app.module (veja acima), por isso é um semi-pousio e permanece o mesmo para todos os componentes, embora a duração da aplicação. Ser capaz de controlar o ciclo de vida dos serviços de componentes é um conceito muito útil, mas pouco apreciado.

DI funciona atribuindo instâncias de serviço ao construtor do componente, identificado por tipos de TypeScript. Além disso, as palavras-chave public atribuir parâmetros automaticamente a this, portanto, não precisamos mais digitar essas linhas chatas this.homeService = homeService.

Dashboard


Clicks since last visit: {{homeService.counter}} Click!

A sintaxe do template do Angular, certamente muito elegante. Eu gosto do atalho [()], que funciona como uma ligação de dados bidirecional, mas, por trás disso, é na verdade um atributo binding + event. Conforme ditado pelo ciclo de vida de nossos serviços, homeService.counter ele reiniciará toda vez que navegarmos para fora de /home, mas de appService.username permanece e é acessível de qualquer lugar.

Reagir

import { observable } from 'mobx' export class HomeStore { @observable counter = 0 increment = () => { this.counter++ } }

Com MobX, precisamos adicionar o decorador @observable a qualquer propriedade que desejamos tornar observável.

@observer export class Home extends React.Component { homeStore: HomeStore componentWillMount() { this.homeStore = new HomeStore() } render() { return } }

Para gerenciar o ciclo de vida adequadamente, precisamos trabalhar um pouco mais do que no exemplo do Angular. Envolvemos o HomeComponent dentro de um Provider, que recebe uma nova instância de HomeStore em cada assembleia.

interface HomeComponentProps { appStore?: AppStore, homeStore?: HomeStore } @inject('appStore', 'homeStore') @observer export class HomeComponent extends React.Component { render() { const { homeStore, appStore } = this.props return

Dashboard

Clicks since last visit: {homeStore.counter} Click! } }

HomeComponent usa o decorador @observer para ouvir as alterações nas propriedades @observable.

O mecanismo sob o capô disso é muito legal, então vamos examinar isso brevemente aqui. O decorador @observable sobrescrever uma propriedade em um objeto com getter e setter, permitindo interceptar chamadas. Quando a função de renderização de um componente aumentado é chamada @observador, as propriedades getters são chamadas e mantêm uma referência ao componente de chamada.

Então, quando setter é chamado e o valor é alterado, as funções de renderização dos componentes que usaram a propriedade na última renderização são chamadas. Agora os dados sobre quais propriedades são usadas são atualizados e todo o ciclo pode ser reiniciado.

Um mecanismo muito simples e de bom desempenho. Explicação mais detalhada Aqui .

O decorador @inyectar 'se utiliza para inyectar instancias appStore y homeStore en los accesorios de HomeComponent . En este punto, cada una de esas tiendas tiene un ciclo de vida diferente. appStore es el mismo durante la vida de la aplicación, pero homeStore` é criado em cada navegação para o caminho “/ home”.

A vantagem disso é que não é necessário limpar as propriedades manualmente, como é o caso quando todos os armazenamentos são globais, o que é doloroso se o caminho for alguma página de 'detalhes' que contém dados completamente diferentes a cada vez.

Resumo: Como o gerenciamento do ciclo de vida do fornecedor é um recurso inerente do DI da Angular, é claro que é mais simples alcançá-lo lá. A versão React também pode ser usada, mas envolve muito mais clichês.

Propriedades Calculadas

Reagir

Vamos começar com React neste, você tem uma solução mais direta.

import { observable, computed, action } from 'mobx' export class HomeStore { import { observable, computed, action } from 'mobx' export class HomeStore { @observable counter = 0 increment = () => { this.counter++ } @computed get counterMessage() { console.log('recompute counterMessage!') return `${this.counter} ${this.counter === 1 ? 'click' : 'clicks'} since last visit` } }

Portanto, temos uma propriedade calculada que se liga a counter e retorna uma mensagem corretamente pluralizada. O resultado de counterMessage é armazenado em cache e recalculado apenas quando counter alterar.

{homeStore.counterMessage} Click!

Em seguida, referimos a propriedade (e o método increment) do modelo JSX. O campo de entrada é controlado pela vinculação a um valor e permite que um método `appStore 'manipule o evento do usuário.

Angular

Para obter o mesmo efeito no Angular, precisamos ser um pouco mais criativos.

import { Injectable } from '@angular/core' import { BehaviorSubject } from 'rxjs/BehaviorSubject' @Injectable() export class HomeService { message = 'Welcome to home page' counterSubject = new BehaviorSubject(0) // Computed property can serve as basis for further computed properties counterMessage = new BehaviorSubject('') constructor() { // Manually subscribe to each subject that couterMessage depends on this.counterSubject.subscribe(this.recomputeCounterMessage) } // Needs to have bound this private recomputeCounterMessage = (x) => { console.log('recompute counterMessage!') this.counterMessage.next(`${x} ${x === 1 ? 'click' : 'clicks'} since last visit`) } increment() { this.counterSubject.next(this.counterSubject.getValue() + 1) } }

Precisamos definir todos os valores que servem de base para uma propriedade calculada como BehaviorSubject. A própria propriedade calculada também é um BehaviorSubject, porque qualquer propriedade calculada pode servir como entrada para outra propriedade calculada.

Claro, RxJS pode fazer muito mais do que apenas isso, mas seria um assunto para um artigo completamente diferente. A desvantagem secundária é que esse uso trivial de RxJS para propriedades calculadas é um pouco mais prolixo do que o exemplo reativo e você precisa gerenciar as assinaturas manualmente (como aqui no construtor).

{ async} Click!

Observe como podemos referenciar o assunto RxJS com |asíncrona . Esse é um toque legal, muito mais curto do que precisar se inscrever em seus componentes. O componente input é conduzido pela diretiva [(ngModel)]. Apesar de parecer estranho, é bastante estiloso. Apenas um açúcar sintático para vincular dados de valor a appService.username e o valor de atribuição automática do evento de entrada do usuário.

Resumo: As propriedades calculadas são mais fáceis de implementar no React / MobX do que no Angular / RxJS, mas o RxJS pode fornecer alguns recursos FRP mais úteis, que podem ser apreciados posteriormente.

Modelos e CSS

Para mostrar como os modelos são empilhados, usaremos o componente de mensagens, que exibe uma lista de mensagens.

Angular

@Component({ selector: 'app-posts', templateUrl: './posts.component.html', styleUrls: ['./posts.component.css'], providers: [ PostsService ] }) export class PostsComponent implements OnInit { constructor( public postsService: PostsService, public appService: AppService ) { } ngOnInit() { this.postsService.initializePosts() } }

Este componente conecta apenas HTML, CSS e serviços injetados e também chama a função para carregar as mensagens da API na inicialização. AppService é um semi-erro definido no módulo de aplicativo, enquanto PostsService é transitório, com uma nova instância criada a cada vez que o componente é criado. O CSS que é referenciado a partir deste componente tem como escopo este componente, o que significa que o conteúdo não pode afetar nada fora do componente.

add

Hello {{appService.username}}

{{post.title}} {{post.name}}

{{post.message}}

No modelo HTML, nos referimos principalmente aos componentes de Material Angular. Para tê-los disponíveis, era necessário incluí-los nas importações app.module (Veja acima). A diretiva *ngFor é usado para repetir o componente md-card para cada posição.

CSS local:

.mat-card { margin-bottom: 1rem; }

O CSS local aumenta apenas uma das classes presentes no componente md-card.

CSS global:

.float-right { float: right; }

Esta classe é definida no arquivo global style.css para que esteja disponível para todos os componentes. Ele pode ser referenciado no formato padrão, class =' float-right '.

CSS compilado:

.float-right { float: right; } .mat-card[_ngcontent-c1] { margin-bottom: 1rem; }

No CSS compilado, podemos ver que o CSS local foi delimitado ao componente renderizado pelo seletor de atributo [_ngcontent-c1]. Cada componente Angular renderizado tem uma classe gerada como esta para fins de escopo CSS.

A vantagem desse mecanismo é que podemos fazer referência a classes normalmente, e o escopo é tratado 'nos bastidores'.

Reagir

import * as style from './posts.css' import * as appStyle from '../app.css' @observer export class Posts extends React.Component { postsStore: PostsStore componentWillMount() { this.postsStore = new PostsStore() this.postsStore.initializePosts() } render() { return } }

No React, novamente, precisamos usar o Provider para tornar a dependência de PostsStore 'transitória'. Também importamos estilos CSS, denominados style e appStyle, para poder usar as classes desses arquivos CSS em JSX.

interface PostsComponentProps { appStore?: AppStore, postsStore?: PostsStore } @inject('appStore', 'postsStore') @observer export class PostsComponent extends React.Component { render() { const { postsStore, appStore } = this.props return

Hello {appStore.username}

{postsStore.posts.map(post => {post.message} )} } }

Naturalmente, o JSX parece muito mais com o JavaScript do que os modelos HTML do Angular, o que pode ser bom ou ruim, dependendo do seu gosto. Em vez da diretiva *ngFor, usamos a construção map para iterar nas postagens.

Agora, Angular pode ser a estrutura que mais promove o TypeScript, mas na verdade é o JSX onde o TypScript realmente se destaca. Com a adição de módulos CSS (importados acima), realmente transforma a codificação de seu modelo em código zen. Cada coisa é verificada. Componentes, atributos e até classes CSS (appStyle.floatRight e style.messageCard, veja abaixo). E, claro, a natureza estreita do JSX incentiva a divisão em componentes e pedaços um pouco mais do que os modelos do Angular.

CSS local:

.messageCard { margin-bottom: 1rem; }

CSS global:

.floatRight { float: right; }

CSS compilado:

.floatRight__qItBM { float: right; } .messageCard__1Dt_9 { margin-bottom: 1rem; }

Como você pode ver, o Loader for CSS Modules faz o postfix de cada classe CSS com um postfix aleatório, o que garante exclusividade. Uma maneira simples de evitar conflitos. As classes são então referenciadas por meio dos objetos importados do pacote da web. Uma possível desvantagem disso pode ser que você não pode criar um CSS com uma classe e aumentá-la, como fizemos no exemplo do Angular. Por outro lado, isso pode ser muito bom, porque força você a encapsular os estilos corretamente.

Resumo: Pessoalmente, gosto de JSX um pouco mais do que de modelos Angular, principalmente devido ao preenchimento de código e ao tipo de suporte de controle. Esse é realmente um recurso matador. O Angular agora tem o compilador AOT, que pode detectar algumas coisas também, o autocompletar de código funciona para cerca de metade das coisas lá também, mas não é tão completo quanto JSX / TypeScript.

GraphQL - Carregando dados

Portanto, decidimos usar GraphQL para armazenar dados para este aplicativo. Uma das maneiras mais fáceis de criar o back-end GraphQL é usar algum BaaS, como Graphcool. Então foi isso que fizemos. Basicamente, você apenas define modelos e atributos e seu CRUD está pronto para usar.

Código Comum

Como parte do código relacionado ao GraphQL é 100% igual para ambas as implementações, não o repetimos duas vezes:

const PostsQuery = gql` query PostsQuery { allPosts(orderBy: createdAt_DESC, first: 5) { id, name, title, message } } `

GraphQL é uma linguagem de consulta destinada a fornecer um conjunto mais rico de funcionalidades em comparação aos terminais RESTful clássicos. Vamos dissecar essa questão em particular.

  • PostsQuery é apenas um nome para esta consulta para referência posterior, você pode nomear qualquer coisa.
  • allPosts é a parte mais importante - refere-se à função de consultar todos os registros com o padrão `Post`. Este nome foi criado pela Graphcool.
  • orderBy e first são parâmetros da função allPosts. createdAt é um dos Post atributos do modelo. first: 5 significa que ele retornará apenas os 5 primeiros resultados da consulta.
  • id, name, title e message são os atributos do modelo Post que queremos ser incluídos no resultado. Outros atributos serão filtrados.

Como você já pode ver, é bastante poderoso. Confira Esta página para se familiarizar mais com as consultas GraphQL.

interface Post { id: string name: string title: string message: string } interface PostsQueryResult { allPosts: Array }

Sim, como bons cidadãos do TypeScript, criamos interfaces para resultados GraphQL.

Angular

@Injectable() export class PostsService { posts = [] constructor(private apollo: Apollo) { } initializePosts() { this.apollo.query({ query: PostsQuery, fetchPolicy: 'network-only' }).subscribe(({ data }) => { this.posts = data.allPosts }) } }

A consulta GraphQL é um RxJS observável e nós o assinamos. Funciona um pouco como uma promessa, mas não funciona, por isso não temos sorte com async/await. Claro que ainda existem prometer , mas não parece ser o caminho Angular de qualquer maneira. Definimos fetchPolicy: 'network-only' porque, neste caso, não queremos armazenar os dados em cache, mas buscá-los novamente a cada vez.

Reagir

export class PostsStore { appStore: AppStore @observable posts: Array = [] constructor() { this.appStore = AppStore.getInstance() } async initializePosts() { const result = await this.appStore.apolloClient.query({ query: PostsQuery, fetchPolicy: 'network-only' }) this.posts = result.data.allPosts } }

A versão React é quase idêntica, mas como apolloClient aqui ele usa promessas, podemos tirar proveito da sintaxe async / await. Existem outras abordagens no React que apenas 'gravam' consultas GraphQL para componentes de ordem superior , mas descobri que misturar muito a camada de dados e a apresentação.

Em resumo: As ideias do RxJS subscribe vs async / await são realmente as mesmas.

GraphQL - Salvando dados

Código Comum

Mais uma vez, algum código GraphQL relacionado:

const AddPostMutation = gql` mutation AddPostMutation($name: String!, $title: String!, $message: String!) { createPost( name: $name, title: $title, message: $message ) { id } } `

O objetivo das mutações é criar ou atualizar registros. Portanto, é benéfico declarar algumas variáveis ​​com a mutação, pois são a forma de passar os dados nela. Portanto, temos as variáveis ​​name, title e message, escrito como String, que precisamos preencher toda vez que chamarmos essa mutação. A função createPost, novamente, é definida pelo Graphcool. Especificamos que as chaves do modelo Post terá valores das variáveis ​​de mutação de saída, e também que queremos o id do Post recém-criado é enviado em troca.

Angular

@Injectable() export class FormService { constructor( private apollo: Apollo, private router: Router, private appService: AppService ) { } addPost(value) { this.apollo.mutate({ mutation: AddPostMutation, variables: { name: this.appService.username, title: value.title, message: value.message } }).subscribe(({ data }) => { this.router.navigate(['/posts']) }, (error) => { console.log('there was an error sending the query', error) }) } }

Quando chamamos apollo.mutate, precisamos fornecer a mutação que chamamos e as variáveis ​​também. Obtemos o resultado na função de retorno de chamada subscribe e usamos o `rotator 'injetado para navegar de volta para a lista de discussão.

Reagir

export class FormStore { constructor() { this.appStore = AppStore.getInstance() this.routerStore = RouterStore.getInstance() this.postFormState = new PostFormState() } submit = async () => { await this.postFormState.form.validate() if (this.postFormState.form.error) return const result = await this.appStore.apolloClient.mutate( { mutation: AddPostMutation, variables: { name: this.appStore.username, title: this.postFormState.title.value, message: this.postFormState.message.value } } ) this.goBack() } goBack = () => { this.routerStore.history.push('/posts') } }

Muito semelhante ao anterior, com a diferença de mais injeção de dependência 'manual' e o uso de async/await.

Em resumo: Novamente, não há muita diferença aqui. subscrever vs async / await é basicamente tudo o que difere.

Formulários

Queremos atingir os seguintes objetivos com os formulários neste aplicativo:

  • Vinculando dados de campos a um modelo
  • Mensagens de validação para cada campo, regras múltiplas
  • Suporte para verificar se todo o formulário é válido

Reagir

export const check = (validator, message, options) => (value) => (!validator(value, options) && message) export const checkRequired = (msg: string) => check(nonEmpty, msg) export class PostFormState { title = new FieldState('').validators( checkRequired('Title is required'), check(isLength, 'Title must be at least 4 characters long.', { min: 4 }), check(isLength, 'Title cannot be more than 24 characters long.', { max: 24 }), ) message = new FieldState('').validators( checkRequired('Message cannot be blank.'), check(isLength, 'Message is too short, minimum is 50 characters.', { min: 50 }), check(isLength, 'Message is too long, maximum is 1000 characters.', { max: 1000 }), ) form = new FormState({ title: this.title, message: this.message }) }

Portanto, a livraria formstate Funciona assim: para cada campo do formulário, defina um FieldState. O parâmetro passado é o valor inicial. O validators recebe uma função, que retorna 'falso' quando o valor é válido e uma mensagem de validação quando o valor é inválido. Com as funções check' y checkRequired`, tudo pode parecer muito declarativo.

Para ter a validação de todo o formulário, é benéfico também envolver esses campos com uma instância FormState, que então fornece a validade adicionada.

@inject('appStore', 'formStore') @observer export class FormComponent extends React.Component { render() { const { appStore, formStore } = this.props const { postFormState } = formStore return

Create a new post

You are now posting as {appStore.username}

A instância FormState fornece propriedades value, onChange e error, que pode ser facilmente usado com qualquer componente front-end.

} }

Quando form.hasError é true, mantemos o botão desativado. O botão Enviar envia o formulário para a mutação GraphQL apresentada acima.

Angular

No Angular, usaremos FormService e FormBuilder, que são partes do pacote @angular/forms.

@Component({ selector: 'app-form', templateUrl: './form.component.html', providers: [ FormService ] }) export class FormComponent { postForm: FormGroup validationMessages = { 'title': { 'required': 'Title is required.', 'minlength': 'Title must be at least 4 characters long.', 'maxlength': 'Title cannot be more than 24 characters long.' }, 'message': { 'required': 'Message cannot be blank.', 'minlength': 'Message is too short, minimum is 50 characters', 'maxlength': 'Message is too long, maximum is 1000 characters' } }

Primeiro, vamos definir as mensagens de validação.

constructor( private router: Router, private formService: FormService, public appService: AppService, private fb: FormBuilder, ) { this.createForm() } createForm() { this.postForm = this.fb.group({ title: ['', [Validators.required, Validators.minLength(4), Validators.maxLength(24)] ], message: ['', [Validators.required, Validators.minLength(50), Validators.maxLength(1000)] ], }) }

Usando FormBuilder, é muito fácil criar a estrutura do formulário, ainda mais sucintamente do que no exemplo React.

get validationErrors() { const errors = {} Object.keys(this.postForm.controls).forEach(key => { errors[key] = '' const control = this.postForm.controls[key] if (control && !control.valid) { const messages = this.validationMessages[key] Object.keys(control.errors).forEach(error => { errors[key] += messages[error] + ' ' }) } }) return errors }

Para obter mensagens de validação de ligação no lugar certo, precisamos fazer algum processamento. Este código é retirado da documentação oficial, com algumas pequenas alterações. Basicamente, no FormService, os campos mantêm referência apenas aos erros ativos, identificados pelo nome do validador, portanto, precisamos fazer a correspondência manual das mensagens necessárias com os campos afetados. Isso não é inteiramente um inconveniente; por exemplo, ele se presta mais facilmente à internacionalização.

onSubmit({ value, valid }) { if (!valid) { return } this.formService.addPost(value) } onCancel() { this.router.navigate(['/posts']) } }

Mais uma vez, quando o formulário for válido, os dados podem ser enviados para a mutação GraphQL.

Create a new post

You are now posting as {{appService.username}}

{{validationErrors['title']}}

{{validationErrors['message']}}

Cancel Submit

O mais importante é referir-se ao formGroup que criamos com FormBuilder, que é a atribuição [formGroup] = 'postForm'. Os campos do formulário estão vinculados ao modelo de formulário por meio da propriedade formControlName. Novamente, desativamos o botão 'Enviar' quando o formulário é inválido. Devemos também adicionar o cheque sujo, porque aqui, o formulário não sujo pode ser inválido. Queremos que o estado inicial do botão seja 'habilitado'.

Em resumo: Essa abordagem para formulários em React e Angular é bastante diferente nas frentes de validação e template. A abordagem Angular envolve um pouco mais de 'mágica' em vez de links diretos, mas, por outro lado, é mais abrangente.

Tamanho do lote

Oh, mais uma coisa. A produção reduziu os tamanhos dos pacotes JS, com configurações padrão para geradores de aplicativos: notavelmente Tree Shaking in React e AOT build em Angular.

  • Angular: 1200 KB
  • Reagir: 300 KB

Bem, não há muita surpresa aqui. Angular sempre foi o mais volumoso.

Ao usar o gzip, os tamanhos caem para 275kb e 127kb, respectivamente.

Apenas tenha em mente que essas são basicamente todas as bibliotecas de fornecedores. A quantidade de código do aplicativo real é mínima em comparação, o que não é o caso em um aplicativo do mundo real. Nesse caso, a proporção provavelmente seria mais próxima de 1: 2 do que de 1: 4. Além disso, quando você começa a incluir muitas bibliotecas de terceiros com o React, o tamanho do pacote também tende a crescer muito rapidamente.

Flexibilidade das bibliotecas vs. robustez da estrutura

Portanto, parece que não fomos capazes (de novo!) De dar uma resposta clara sobre se Angular ou React é melhor para desenvolvimento web.

Acontece que os fluxos de trabalho de desenvolvimento no React e no Angular podem ser muito semelhantes, dependendo das bibliotecas com as quais escolhemos usar o React. Portanto, é principalmente uma questão de preferência pessoal.

Se você gosta de pilhas prontas, injeção de dependência poderosa e o plano para usar alguns recursos do RxJS, escolha Angular.

Se você gosta de jogar e construir sua própria pilha, como a simplicidade do JSX, e prefere propriedades computáveis ​​mais simples, selecione React / MobX.

Mais uma vez, você pode obter o código-fonte completo do aplicativo neste artigo Aqui Y Aqui .

Ou, se preferir exemplos maiores e do RealWorld:

  • RealWorld Angular 4+
  • RealWorld React / MobX

Primeiro, escolha seu paradigma de programação

A programação com React / MobX é, na verdade, mais semelhante a Angular do que React / Redux. Existem algumas diferenças notáveis ​​em modelos e tratamento de dependências, mas eles têm o mesmo paradigma mutável / vinculação de dados .

React / Redux com seu paradigma imutável / unidirecional é uma besta completamente diferente.

Não se deixe enganar pelo tamanho reduzido da biblioteca Redux. Pode ser pequeno, mas é uma estrutura de qualquer maneira. A maioria das melhores práticas do Redux hoje se concentra no uso de bibliotecas compatíveis com redux, como Redux Saga para código assíncrono e pesquisa de dados, Redux Form para gerenciamento de formulários, Selecione novamente para seletores memorizados (valores Redux calculados). Y Recompor , entre outros, para uma gestão mais precisa do ciclo de vida. Além disso, há uma mudança na comunidade Redux de Immutable.js para Ramda ou Lodash / fp , que funcionam com objetos JS simples em vez de convertê-los.

Um bom exemplo de Redux moderno é o conhecido React Boilerplate . É uma pilha de desenvolvimento formidável, mas se você der uma olhada, é realmente muito, muito diferente de tudo que vimos neste post até agora.

Eu sinto que o Angular está recebendo um tratamento injusto da parte mais vocal da comunidade JavaScript. Muitas pessoas expressando insatisfação com ele provavelmente não apreciam a grande mudança que aconteceu entre o antigo AngularJS e o Angular de hoje. Na minha opinião, é um quadro muito limpo e produtivo que tomaria o mundo de assalto se tivesse surgido 1-2 anos antes.

No entanto, a Angular vem ganhando espaço, principalmente no mundo corporativo, com grandes equipes e necessidades de padronização e suporte de longo prazo. Ou, dito de outra forma, Angular é a maneira como os engenheiros do Google acham que o desenvolvimento web deve ser feito, se ainda for o caso.

Quanto ao MobX, uma avaliação semelhante se aplica. Muito legal, mas não muito apreciado.

diferença entre um s corp e ac corp

Resumindo: antes de escolher entre React e Angular, primeiro escolha seu paradigma de programação.

mutável / vinculação de dados ou imutável / unidirecional , esse parece ser o problema real.

Os pais falam sobre por que as crianças não devem ser agredidas: 'É completamente inútil'

Família

Os pais falam sobre por que as crianças não devem ser agredidas: 'É completamente inútil'
Atualizar automaticamente o Elastic Stack com Ansible Playbooks

Atualizar automaticamente o Elastic Stack com Ansible Playbooks

Tecnologia

Publicações Populares
A inegável importância de um plano de negócios
A inegável importância de um plano de negócios
Teste de unidade .NET: gaste com antecedência para economizar mais tarde
Teste de unidade .NET: gaste com antecedência para economizar mais tarde
Tanzânia tomará posse do novo presidente na sexta-feira após a morte de Magufuli
Tanzânia tomará posse do novo presidente na sexta-feira após a morte de Magufuli
Tutorial de física de videogame - Parte I: Uma introdução à dinâmica de corpos rígidos
Tutorial de física de videogame - Parte I: Uma introdução à dinâmica de corpos rígidos
Estilos tipográficos para a web e design editorial e impresso
Estilos tipográficos para a web e design editorial e impresso
 
Como os PMs podem estar prontos para a automação de processos robóticos
Como os PMs podem estar prontos para a automação de processos robóticos
IU futura e sandboxes de fim de design
IU futura e sandboxes de fim de design
Protótipo com facilidade - um tutorial do InVision Studio
Protótipo com facilidade - um tutorial do InVision Studio
Táticas e estratégias de negociação de fusões e aquisições: dicas de um profissional
Táticas e estratégias de negociação de fusões e aquisições: dicas de um profissional
Esses profissionais de saúde preferem ser demitidos do que vacinados
Esses profissionais de saúde preferem ser demitidos do que vacinados
Publicações Populares
  • jira é uma ferramenta de gerenciamento de projetos?
  • modelo de documento de design de software simples
  • qual é o algoritmo bitcoin
  • design gráfico não é arte
  • por que a proporção é importante em um design
  • cor verde do ano
  • estrutura da entidade onde na lista
Categorias
  • Talento Ágil
  • Lucratividade E Eficiência
  • Móvel
  • Estilo De Vida
  • © 2022 | Todos Os Direitos Reservados

    portaldacalheta.pt