menu

SHARKLABS

Comparação: Vue Router vs React Router

/
/
Comparação: Vue Router vs React Router
bookmark React.js, Vue.js access_time

Vue.js e React.js

Eu trabalho com Vue.js desde 2017, mas já faz alguns meses que estou participando de um projeto com React.js e quero compartilhar mais detalhes sobre essa experiência.

O objetivo deste artigo é comparar as bibliotecas Vue Router com React Router. Importante destacar que ambas bibliotecas são muito boas e cada uma tem suas vantagens.

Por isso meu propósito não é dizer qual é "melhor" ou "pior". Meu propósito é apresentar o funcionamento de cada uma para que você decida qual delas se adapta melhor ao seu projeto.

Exemplo Prático

Eu vou criar um pequeno exemplo que tenha as seguintes rotas:

  • Home: Página inicial com alguns links.
  • Login: Tela de login (neste caso um login fake só para demonstração).
  • AboutCompany e AboutMe: Aqui há duas rotas que compartilham um mesmo layout (nested routes).
  • User: Tela que exibe um usuário de acordo com os parâmetros passados na URL.
  • Forbidden: Tela que o usuário é redirecionado quando tenta acessar alguma rota restrita a usuários logados.

Neste exemplo, somente as rotas AboutCompany, AboutMe e User são protegidas, ou seja, só podem acessadas por usuários autenticados.

Agora eu vou mostrar como fica este exemplo com Vue Router e posteriormente como fica com React Router.

Exemplo com Vue Router

Antes de continuar, você precisa de um projeto com Vue.js e Vue Router configurados. Se você tem dúvidas sobre isso, clique aqui.

Arquivo "/src/main.js":

import Vue from 'vue';
import App from './App.vue';
import router from './router';

Vue.config.productionTip = false;

new Vue({
  router,
  render: (h) => h(App),
}).$mount('#app');

Arquivo "/src/router/index.js":

import Vue from 'vue';
import VueRouter from 'vue-router';

import Home from '@/views/Home.vue';
import Login from '@/views/Login.vue';
import User from '@/views/User.vue';
import About from '@/views/About.vue';
import AboutMe from '@/views/AboutMe.vue';
import AboutCompany from '@/views/AboutCompany.vue';
import Forbidden from '@/views/Forbidden.vue';

const routes = [
  { path: '/', name: 'Home', component: Home, meta: { auth: false } },
  { path: '/login', name: 'Login', component: Login, meta: { auth: false } },
  { path: '/forbidden', name: 'Forbidden', component: Forbidden, meta: { auth: false } },
  { path: '/users/:id', name: 'User', component: User, meta: { auth: true } },
  {
    path: '/about',
    name: 'About',
    component: About,
    children: [
      {
        path: '/about/me',
        name: 'AboutMe',
        component: AboutMe,
        meta: { auth: true },
      },
      {
        path: '/about/company',
        name: 'AboutCompany',
        component: AboutCompany,
        meta: { auth: true },
      },
    ],
  },
];

Vue.use(VueRouter);

const router = new VueRouter({ routes });

router.beforeEach((to, from, next) => {
  if (to.meta.auth) {
    const logged = window.localStorage.getItem('logged') === 'true';
    if (!logged) {
      next('/forbidden');
      return;
    }
  }
  next();
});

export default router;

Arquivo "/src/App.vue":

<template>
  <div id="app">
    <router-view />
  </div>
</template>

<script>
export default {
  name: 'App',
};
</script>

Arquivo "/src/views/Home.vue":

<template>
  <div>
    <h2>Home</h2>
    <div>Logged: {{ logged }}</div>
    <br />
    <div>
      <router-link to="/login">Login</router-link>
    </div>
    <div>
      <router-link to="/about/me">About Me</router-link>
    </div>
    <div>
      <router-link to="/about/company">About Company</router-link>
    </div>
    <div>
      <router-link to="/users/1?name=John">User #1</router-link>
    </div>
    <div>
      <router-link to="/users/2?name=Paul">User #2</router-link>
    </div>
  </div>
</template>

<script>
export default {
  name: 'Home',
  data: () => ({
    logged: window.localStorage.getItem('logged') === 'true',
  }),
};
</script>

Arquivo "/src/views/Login.vue":

<template>
  <div>
    <h2>Login</h2>
    <div>
      <button @click="fakeLogin" v-if="!logged">Fake login</button>
      <button @click="fakeLogout" v-else>Fake logout</button>
    </div>
    <div>
      <router-link to="/">Back to Home</router-link>
    </div>
  </div>
</template>

<script>
export default {
  name: 'Login',
  data: () => ({
    logged: window.localStorage.getItem('logged') === 'true',
  }),
  methods: {
    fakeLogin() {
      this.logged = true;
      window.localStorage.setItem('logged', true);
    },
    fakeLogout() {
      this.logged = false;
      window.localStorage.setItem('logged', false);
    },
  },
};
</script>

Arquivo "/src/views/About.vue" e que serve de base para rotas filhas (AboutCompany e AboutMe):

<template>
  <div>
    <h2>About</h2>
    <router-view />
    <div>
      <router-link to="/">Back to Home</router-link>
    </div>
  </div>
</template>

<script>
export default {
  name: 'About',
};
</script>

Arquivo "/src/views/AboutCompany.vue":

<template>
  <div>
    <h3>AboutCompany</h3>
  </div>
</template>

<script>
export default {
  name: 'AboutCompany',
};
</script>

Arquivo "/src/views/AboutMe.vue":

<template>
  <div>
    <h3>AboutMe</h3>
  </div>
</template>

<script>
export default {
  name: 'AboutMe',
};
</script>

Arquivo "/src/views/User.vue" que exibe os dados de usuário conforme parâmetros passados na URL (params e query):

<template>
  <div>
    <h2>Users</h2>
    <div>id: {{ $route.params.id }}</div>
    <div>name: {{ $route.query.name }}</div>
    <div>
      <router-link to="/">Back to Home</router-link>
    </div>
  </div>
</template>

<script>
export default {
  name: 'Users',
};
</script>

Arquivo "/src/views/Forbidden.vue":

<template>
  <div>
    <h2>Forbidden</h2>
    <div>Please sign in to access this page</div>
    <div>
      <router-link to="/login">Login</router-link>
    </div>
  </div>
</template>

<script>
export default {
  name: 'Forbidden',
};
</script>

Exemplo com React Router

Agora vou mostrar o mesmo exemplo com React Router. Antes de continuar, você precisa de um projeto com React.js e React Router configurados. Se você tem dúvidas sobre isso, clique aqui para entender como instalar o React.js e clique aqui para entender como instalar o React Router.

Arquivo "/src/index.js":

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.js';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

Arquivo "/src/App.js":

import React from 'react';
import { BrowserRouter, Switch, Route, Redirect } from 'react-router-dom';

import Home from './Home.js';
import Login from './Login.js';
import About from './About.js';
import User from './User.js';
import Forbidden from './Forbidden.js';

const PrivateRoute = ({ component: Component, ...rest }) => {
  const render = (props) => {
    if (window.localStorage.getItem('logged') === 'true') {
      return <Component {...props} />;
    }
    return <Redirect to="/forbidden" />;
  };
  return <Route {...rest} render={render} />;
};

export default function App() {
  return (
    <BrowserRouter>
      <Switch>
        <Route exact path="/" component={Home} />
        <Route exact path="/login" component={Login} />
        <Route exact path="/forbidden" component={Forbidden} />
        <PrivateRoute exact path="/users/:id" component={User} />
        <PrivateRoute strict path="/about" component={About} />
      </Switch>
    </BrowserRouter>
  );
}

Arquivo "/src/Home.js":

import React, { useState } from 'react';
import { Link } from 'react-router-dom';

export default function Home(props) {
  const [logged] = useState(window.localStorage.getItem('logged') === 'true');

  return (
    <div>
      <h2>Home</h2>
      <div>Logged: {JSON.stringify(logged)}</div>
      <br />
      <div>
        <Link to="/login">Login</Link>
      </div>
      <div>
        <Link to="/about/me">About Me</Link>
      </div>
      <div>
        <Link to="/about/company">About Company</Link>
      </div>
      <div>
        <Link to="/users/1?name=John">User #1</Link>
      </div>
      <div>
        <Link to="/users/2?name=Paul">User #2</Link>
      </div>
    </div>
  );
}

Arquivo "/src/Login.js":

import React, { useState } from 'react';
import { Link } from 'react-router-dom';

export default function Login() {
  const [logged, setLogged] = useState(window.localStorage.getItem('logged') === 'true');

  const fakeLogin = () => {
    setLogged(true);
    window.localStorage.setItem('logged', true);
  };

  const fakeLogout = () => {
    setLogged(false);
    window.localStorage.setItem('logged', false);
  };

  const action = () => {
    if (logged) {
      return <button onClick={fakeLogout}>Fake logout</button>;
    } else {
      return <button onClick={fakeLogin}>Fake login</button>;
    }
  };

  return (
    <div>
      <h2>Login</h2>
      <div>{action()}</div>
      <div>
        <Link to="/">Back to Home</Link>
      </div>
    </div>
  );
}

Arquivo "/src/About.js" e que serve de base para rotas filhas (AboutCompany e AboutMe):

import React from 'react';
import { Switch, Route, Link } from 'react-router-dom';
import AboutMe from './AboutMe.js';
import AboutCompany from './AboutCompany.js';

export default function About() {
  return (
    <div>
      <h2>About</h2>
      <Switch>
        <Route exact path="/about/me" component={AboutMe}></Route>
        <Route exact path="/about/company" component={AboutCompany}></Route>
      </Switch>
      <div>
        <Link to="/">Back to Home</Link>
      </div>
    </div>
  );
}

Arquivo "/src/AboutCompany.js":

import React from 'react';

export default function AboutCompany() {
  return (
    <div>
      <h3>AboutCompany</h3>
    </div>
  );
}

Arquivo "/src/AboutMe.js":

import React from 'react';

export default function AboutMe() {
  return (
    <div>
      <h3>AboutMe</h3>
    </div>
  );
}

Arquivo "/src/User.js":

import React from 'react';
import { Link, useLocation, useParams } from 'react-router-dom';

export default function User() {
  const params = useParams();
  const location = useLocation();
  const query = new URLSearchParams(location.search);

  return (
    <div>
      <h2>Users</h2>
      <div>id: {params.id}</div>
      <div>name: {query.get('name')}</div>
      <div>
        <Link to="/">Back to Home</Link>
      </div>
    </div>
  );
}

Arquivo "/src/Forbidden.js":

import React from 'react';
import { Link } from 'react-router-dom';

export default function Forbidden() {
  return (
    <div>
      <div>
        <h2>Forbidden</h2>
        <div>Please sign in to access this page</div>
        <div>
          <Link to="/login">Login</Link>
        </div>
      </div>
    </div>
  );
}

Diferenças entre Vue Router e React Router

Embora sejam bibliotecas muito parecidas, mas há algumas características diferentes.

Na minha opinião a principal diferença entre elas é na configuração das rotas. No Vue Router a configuração é feita por um arquivo JavaScript com um objeto (arquivo "/src/router/index.js") .

Por outro lado no React Router as rotas são configuradas diretamente na declaração do componente "Route". Mas é importante destacar que é possível criar um arquivo de configuração e gerar esse componente dinamicamente.

Ainda sobre essa questão a configuração das rotas, veja que no Vue Router o redirecionamento, caso um usuário não esteja autenticado, é feito por meio do evento beforeEach.

Já no React Router esse redirecionamento de usuários não autenticados é feito por meio da função render do componente Route.

Outra diferença é que no Vue Router você consegue acessar os valores da URL por meio dos variáveis $route.params e $route.query.

Já no React Router você consegue usar a função useParams para os parâmetros, mas não há uma implementação para acessar a query. Por isso precisamos usar a classe URLSearchParams do navegador.

Na minha opinião, estas são as diferenças mais importantes. As demais diferenças estão relacionadas a sintaxe e detalhes de cada framework.

Por fim

Só para destacar que neste artigo eu utilizei as seguintes versões de cada biblioteca:

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