menu

SHARKLABS

Para Programadores Vue.js: Comparação com React

/
/
Para Programadores Vue.js: Comparação com React
bookmark React.js, Vue.js access_time

Do Vue.js para React.js

Vue.js e React.js são ótimas ferramentas que têm várias funcionalidades em comum, porém algumas coisas são diferentes.

Eu programo com Vue.js desde 2017 e desde então participei de vários projetos. Não é novidade para ninguém que gosto muito do framework e sempre que possível compartilho minhas experiências aqui no blog.

Eu aprendi React.js recentemente e por isso decidi escrever este artigo com o objetivo ajudar programadores que tenham conhecimento de Vue.js a entender alguns conceitos do React.js. Ou seja, é uma comparação partindo do Vue.js para o React.js.

Criando um projeto

Para criar um projeto com Vue.js, basta executar os seguintes comandos:

npm install -g @vue/cli
vue create PROJECT_NAME

Uma coisa interessante do instalador do Vue.js, é que você pode escolher algumas opções antes de iniciar a instalação.

Agora vamos ver o comando para criar um projeto com React.js:

npx create-react-app PROJECT_NAME

Este comando vai configurar um projeto padrão com React.js, porém para personalizar a instalação é um pouco diferente. Ou você passa alguns parâmetros na linha de comando, ou você usa a opção Eject depois da instalação.

Vale ressaltar que a opção Eject é uma opção avançada e que não tem volta. Se você quer saber mais sobre isso clique aqui

HTML com Dados

Talvez essa seja a principal diferença entre as duas ferramentas.

Com Vue.js o JavaScript fica bem separado do HTML e você usa diretivas para fazer condições (v-if) e laços de repetição (v-for). Por exemplo:

<template>
  <div>
    <div v-if="warning">Warning message</div>
    <div v-else="warning">No messages</div>
    <div v-for="user in users" :key="user">{{ user }}</div>
  </div>
</template>

<script>
export default {
  data: () => ({
    warning: true,
    users: ['john', 'paul'],
  }),
};
</script>

Agora o mesmo exemplo com React.js:

import React, { useState } from 'react';

export default function () {
  let [warning] = useState(true);
  let [users] = useState(['john', 'paul']);

  return (
    <div>
      {warning ? <div>Warning message</div> : <div>No messages</div>}
      {users.map((user) => (
        <div key={user}>{user}</div>
      ))}
    </div>
  );
}

Veja que o React.js "mistura" JavaScript com HTML, o nome disso é JSX. Se você deseja saber mais sobre JSX clique neste link.

Métodos e eventos

Agora vou mostrar um exemplo de um pequeno contator feito com ambas ferramentas. Primeiramente com Vue.js:

<template>
  <div>
    <button @click="increment">Increment</button>
    <span>{{ counter }} </span>
  </div>
</template>

<script>
export default {
  data: () => ({
    counter: 0,
  }),
  methods: {
    increment() {
      this.counter++;
    },
  },
};
</script>

Agora com React.js:

import React, { useState } from 'react';

export default function () {
  let [counter, setCounter] = useState(0);

  let increment = () => {
    setCounter(counter + 1);
  };

  return (
    <div>
      <button onClick={increment}>Increment</button>
      <span>{counter}</span>
    </div>
  );
}

Veja que para alterar os estados do React é necessário importar a função setCounter. Já no Vue.js é possível alterar o conteúdo da variável diretamente. Importante frisar essa diferença, uma vez que isso é uma dúvida comum para quem já conhece Vue.js e vai iniciar com React.js.

Outros detalhes sobre a manipulação de eventos com React estão neste link.

Diretiva v-model

Com Vue.js temos a diretiva v-model que funciona como um syntax sugar que relaciona o valor de uma variável e escuta seus eventos.

Já no React.js não temos o recurso de diretivas e por isso precisamos adicionar esse comportamento manualmente.

Veja um exemplo com Vue.js:

<template>
  <div>
    <input type="text" v-model="name" />
    <input type="text" :value="name" @input="name = $event.target.value" />
  </div>
</template>

<script>
export default {
  data: () => ({
    name: 'Gabriel Willemann',
  }),
};
</script>

Primeiramente temos um input com v-model e depois temos outro input só para demonstrar como funcionaria sem o syntax sugar. Vale destacar que ambos tem o mesmo comportamento.

Agora um exemplo com React.js:

import React, { useState } from 'react';

export default function () {
  let [name, setName] = useState('Gabriel Willemann');

  return (
    <div>
      <input type="text" value={name} onChange={(e) => setName(e.target.value)} />
      <input type="text" value={name} onChange={(e) => setName(e.target.value)} />
    </div>
  );
}

Veja que há várias diferenças no código entre as duas ferramentas. A primeira é que o React.js usa o evento onchange e o Vue.js usa o evento oninput.

No HTML/JavaScript puro existe o evento onchange e oninput, porém são eventos diferentes. O onchange é acionado quando a alteração termina e o oninput é acionado a cada tecla digitada.

O Vue.js segue esse padrão, porém o React.js não segue. Dentro do React.js o evento onchange se comporta igual o evento oninput. Para detalhes sobre isso clique aqui.

Outra diferença é de sintaxe, o Vue.js usa o prefixo ":" para relacionar propriedades e o prefixo "@" para relacionar eventos.

Já no React.js não tem essa diferença, ambos os casos você declara com "={}". É claro que nas propriedades você passa uma variável e nos eventos você passa uma função.

Computed Properties

Segue exemplo de uma computed property em Vue.js:

<template>
  <div>
    <button @click="increment">Increment</button>
    <div>{{ counter }}</div>
    <div>{{ double }}</div>
  </div>
</template>

<script>
export default {
  data: () => ({
    counter: 0,
  }),
  computed: {
    double() {
      return this.counter * 2;
    },
  },
  methods: {
    increment() {
      this.counter++;
    },
  },
};
</script>

Para fazer algo assim no React.js você deve utilizar a função useMemo;

import React, { useState, useMemo } from 'react';

export default function () {
  let [counter, setCounter] = useState(0);

  let increment = () => {
    setCounter(counter + 1);
  };

  let double = useMemo(() => {
    return counter * 2;
  }, [counter]);

  return (
    <div>
      <button onClick={increment}>Increment</button>
      <div>{counter}</div>
      <div>{double}</div>
    </div>
  );
}

Components / Props / Slots / Events

Segue um exemplo de um componente com propriedade, slot e evento em Vue.js. Veja o arquivo Hello.vue:

<template>
  <div @click="$emit('click', 'component clicked')">
    <h1>Hello {{ name }}</h1>
    <slot />
  </div>
</template>

<script>
export default {
  props: ['name'],
};
</script>

Arquivo App.vue:

<template>
  <div>
    <Hello name="Gabriel" @click="showMessage">
      <p>About me: Lorem ipsum dolor sit amet</p>
    </Hello>
  </div>
</template>

<script>
import Hello from './Hello.vue';

export default {
  components: { Hello },
  methods: {
    showMessage(message) {
      console.log(message);
    },
  },
};
</script>

Agora o mesmo exemplo com React. Veja o arquivo Hello.js:

import React from 'react';

export default function (props) {
  return (
    <div onClick={() => props.onClick('component clicked')}>
      <h1>Hello {props.name}</h1>
      {props.children}
    </div>
  );
}

Arquivo App.js

import React from 'react';
import Hello from './Hello';

export default function () {
  let showMessage = (message) => {
    console.log(message);
  };

  return (
    <div>
      <Hello name="Gabriel" onClick={showMessage}>
        <p>About me: Lorem ipsum dolor sit amet</p>
      </Hello>
    </div>
  );
}

A principal diferença aqui é que o React.js não obriga a declarar as propriedades que serão aceitas, ele simplesmente aceita qualquer argumento.

Lifecycle Events

Outro ponto que gera bastante dúvidas para quem está acostumado com Vue.js são os eventos do componente (Lifecycle Events).

Em Vue.js o exemplo fica da seguinte maneira:

<template>
  <div>testing</div>
</template>

<script>
export default {
  mounted() {
    console.log('mounted');
  },
  beforeDestroy() {
    console.log('before-destroy');
  },
};
</script>

Já com React.js precisamos usar a função useEffect, que monitora todas as alterações na renderização e pode funcionar semelhante aos Lifecycle Events do Vue.js. Veja o exemplo a seguir:

import React, { useEffect } from 'react';

export default function () {
  useEffect(() => {
    console.log('mounted');
    return () => {
      console.log('before-destroy');
    };
  }, []);

  return <div>testing</div>;
}

Watchers

Como falei anteriormente a função useEffect monitora todas as alterações na renderização e também pode funcionar de maneira semelhante ao Watchers do Vue.js.

Segue um exemplo com Watchers em Vue.js:

<template>
  <div>
    <input type="text" v-model="name" />
  </div>
</template>

<script>
export default {
  data: () => ({
    name: 'Gabriel Willemann',
  }),
  watch: {
    name(newValue) {
      console.log(`name: ${newValue}`);
    },
  },
};
</script>

Agora o mesmo exemplo com React.js:

import React, { useEffect, useState } from 'react';

export default function () {
  let [name, setName] = useState('Gabriel Willemann');

  useEffect(() => {
    console.log(`name: ${name}`);
  }, [name]);

  return (
    <div>
      <input type="text" value={name} onChange={(e) => setName(e.target.value)} />
    </div>
  );
}

CSS

Enquanto no Vue.js podemos declarar um tag Style dentro do Single File Component, no React.js não temos exatamente essa mesma função.

Porém, isso pode ser contornado de outras maneiras com React.js, segue algumas alternativas:

Outro ponto importante é que no React.js o atributo class deve ser substituído pelo atributo className, porque a palavra class é reservada no JavaScript.

Por fim

Por fim, quero deixar claro que ambas ferramentas são muito boas e contam com muitas vantagens.

Dúvidas ou sugestões é só entrar em contato. Abraço.

Autor
"Any fool can write code that a computer can understand. Good programmers write code that humans can understand." Martin Fowler