Voltar ao blog

Compartilhe este artigo

React Server Components (RSC)

React Server Components (RSC)

Já se perguntou por que sua aplicação React, mesmo com otimizações, ainda demora um pouco para carregar, especialmente em conexões mais lentas?

MonitorFrontend
J
Jonh Alex
19 min de leitura

React Server Components (RSC)

Introdução

Já se perguntou por que sua aplicação React, mesmo com otimizações, ainda demora um pouco para carregar, especialmente em conexões mais lentas? A experiência do usuário (UX) sofre, a taxa de rejeição aumenta, e a performance da sua aplicação impacta diretamente os resultados.

A busca incessante por uma experiência web mais rápida e fluida levou a inovações como o Server-Side Rendering (SSR). Mas e se pudéssemos levar o conceito de renderização no servidor um passo adiante, renderizando partes específicas da nossa interface no servidor, sem a complexidade e as limitações do SSR tradicional?

É aqui que entram os React Server Components (RSC). Eles estão ganhando força rapidamente porque oferecem uma nova maneira de construir aplicações React, permitindo renderizar componentes no servidor e enviar apenas o resultado serializado para o cliente, reduzindo o tamanho do bundle JavaScript e melhorando significativamente o First Contentful Paint (FCP).

Neste artigo, vamos mergulhar de cabeça nos React Server Components, explorando o que são, como funcionam, seus benefícios e limitações, e como você pode começar a utilizá-los para otimizar suas aplicações React. Prepare-se para uma jornada técnica, com exemplos práticos e dicas para evitar armadilhas comuns.

Ao final desta leitura, você será capaz de:

  • Entender o conceito e a arquitetura dos React Server Components.
  • Implementar RSCs em seus projetos React.
  • Avaliar os prós e contras do uso de RSCs para otimizar sua aplicação.
  • Identificar cenários onde RSCs podem trazer o maior impacto.
  • Navegar pelo ecossistema e recursos disponíveis para RSCs.

O que mudou? / O que é?

Antes dos React Server Components, a renderização de aplicações React era predominantemente focada no cliente (Client-Side Rendering - CSR) ou no servidor (Server-Side Rendering - SSR).

  • Client-Side Rendering (CSR): O navegador baixa um bundle JavaScript, executa-o e renderiza a interface do usuário no cliente. Isso pode levar a um atraso no FCP, especialmente em aplicações grandes e complexas.
  • Server-Side Rendering (SSR): O servidor renderiza a interface do usuário em HTML e envia para o cliente. Isso melhora o FCP, mas adiciona complexidade ao servidor e pode afetar o TTFB (Time to First Byte).

O SSR resolveu parcialmente o problema de SEO e tempo de carregamento inicial, mas introduziu novos desafios, como a necessidade de manter o servidor em execução, lidar com a hidratação (hydration) no cliente e o aumento da complexidade do código.

React Server Components (RSC) representam uma evolução nesse cenário. Eles introduzem a capacidade de renderizar partes da aplicação no servidor e partes no cliente, de forma granular. Imagine ter a flexibilidade de executar código diretamente no servidor, acessando bancos de dados e APIs, sem precisar enviar esse código para o navegador.

Principais Características:

  • Renderização Híbrida: RSCs permitem renderizar alguns componentes no servidor e outros no cliente, oferecendo o melhor dos dois mundos.
  • Zero JavaScript para o Cliente: Componentes renderizados no servidor não enviam código JavaScript para o cliente, reduzindo o tamanho do bundle e melhorando o tempo de carregamento.
  • Acesso Direto ao Backend: Componentes renderizados no servidor podem acessar diretamente bancos de dados e APIs sem precisar de uma API intermediária.
  • Atualizações Parciais: As atualizações no servidor são enviadas como um formato de dados otimizado, permitindo atualizações parciais da interface do usuário sem recarregar a página inteira.
  • Streaming: O servidor pode enviar partes da interface do usuário à medida que elas são renderizadas, melhorando a percepção de velocidade.

Por que desenvolvedores estão discutindo?

A comunidade de desenvolvedores está animada com os RSCs porque eles abordam diretamente os desafios de performance em aplicações React. A promessa de reduzir o tamanho do bundle JavaScript, melhorar o FCP e simplificar o acesso ao backend é extremamente atraente.

Além disso, os RSCs abrem novas possibilidades para a arquitetura de aplicações React, permitindo construir interfaces mais complexas e interativas com melhor performance. A discussão gira em torno de como integrar os RSCs em projetos existentes, quais são as melhores práticas e como lidar com as novas complexidades que eles introduzem. A adoção inicial está sendo impulsionada por frameworks como Next.js, que estão integrando os RSCs em suas arquiteturas.

Aspectos Técnicos

A implementação dos React Server Components envolve alguns conceitos e detalhes técnicos importantes.

Arquitetura:

A arquitetura básica de uma aplicação com RSCs envolve o seguinte:

  1. Componentes Servidor (Server Components): São componentes que são renderizados exclusivamente no servidor. Eles podem acessar bancos de dados e APIs diretamente.
  2. Componentes Cliente (Client Components): São componentes que são renderizados no cliente. Eles podem usar hooks do React (useState, useEffect, etc.) e lidar com interações do usuário.
  3. Serialização: O servidor serializa o resultado da renderização dos componentes servidor em um formato de dados otimizado.
  4. Hidratação (Hydration): O cliente recebe os dados serializados do servidor e os utiliza para atualizar a interface do usuário. Client Components podem então be rendered com a informação previamente renderizada do server.

Código Examples:

Vamos começar com um exemplo simples de um componente servidor:

// src/components/ServerComponent.tsx
import { db } from '../lib/db'; // Simulação de um acesso ao banco de dados
 
export default async function ServerComponent() {
  const data = await db.getData(); // Busca de dados no banco de dados (simulado)
 
  return (
    <div>
      <h1>Dados do Servidor</h1>
      <p>Nome: {data.name}</p>
      <p>Email: {data.email}</p>
    </div>
  );
}

Este componente ServerComponent busca dados de um banco de dados (simulado) e os renderiza. Observe que este componente é assíncrono (async function) e pode executar código no servidor sem enviar esse código para o cliente. É importante notar que você não pode usar hooks do React nesse componente.

Agora, vamos criar um componente cliente:

// src/components/ClientComponent.tsx
'use client'; // Marca este componente como um componente cliente
 
import { useState } from 'react';
 
export default function ClientComponent() {
  const [count, setCount] = useState(0);
 
  return (
    <div>
      <p>Contador: {count}</p>
      <button onClick={() => setCount(count + 1)}>Incrementar</button>
    </div>
  );
}

Este componente ClientComponent usa o hook useState para manter um estado local e interagir com o usuário. A diretiva 'use client' é crucial para marcar este componente como um componente cliente.

Finalmente, podemos combinar esses componentes em um componente pai:

// src/app/page.tsx
import ServerComponent from '../components/ServerComponent';
import ClientComponent from '../components/ClientComponent';
 
export default function Page() {
  return (
    <div>
      <ServerComponent />
      <ClientComponent />
    </div>
  );
}

Neste exemplo, o componente Page renderiza tanto o ServerComponent quanto o ClientComponent. O ServerComponent será renderizado no servidor e o ClientComponent será renderizado no cliente.

Comparações com alternativas:

  • SSR (Server-Side Rendering): Enquanto SSR renderiza a página inteira no servidor, RSCs permitem renderizar partes da página no servidor, oferecendo mais flexibilidade e granularidade. SSR normalmente envolve a hidratação completa no cliente, o que pode ser custoso. RSCs minimizam a hidratação, pois apenas componentes cliente precisam ser hidratados.

  • Static Site Generation (SSG): SSG gera páginas estáticas em tempo de build. RSCs permitem renderizar partes da página em tempo de requisição, oferecendo mais dinamismo. SSG é ideal para conteúdo que não muda frequentemente, enquanto RSCs são mais adequados para conteúdo dinâmico.

Breaking changes ou considerações importantes:

  • Diretiva 'use client': É fundamental marcar explicitamente os componentes cliente com a diretiva 'use client'. Se você esquecer, pode ter comportamentos inesperados.
  • Comunicação entre componentes: A comunicação entre componentes servidor e cliente requer cuidado. Você não pode simplesmente passar funções de um componente servidor para um componente cliente. Você precisa serializar os dados e passá-los como props.
  • Hooks: Hooks do React (useState, useEffect, etc.) só podem ser usados em componentes cliente.
  • Context API: O Context API funciona de forma diferente em componentes servidor e cliente. Você precisa ter cuidado ao compartilhar dados entre os dois tipos de componentes.
  • Gerenciamento de estado: Você não pode usar gerenciadores de estado globais (Redux, Zustand, etc.) diretamente em componentes servidor. Você precisa buscar os dados do gerenciador de estado em um componente cliente e passá-los como props para o componente servidor.

Na Prática

Vamos construir um exemplo prático para ilustrar o uso de React Server Components. Imagine que você está construindo um blog e deseja exibir uma lista de posts do blog. Você quer que a lista de posts seja renderizada no servidor para melhorar o FCP, mas também quer ter um botão para atualizar a lista de posts no cliente.

Código funcional completo:

Primeiro, vamos criar um componente servidor para buscar e renderizar a lista de posts:

// src/components/PostList.tsx
import { getPosts } from '../lib/api'; // Simulação de uma chamada à API
 
export default async function PostList() {
  const posts = await getPosts();
 
  return (
    <div>
      <h2>Últimos Posts</h2>
      <ul>
        {posts.map(post => (
          <li key={post.id}>
            <h3>{post.title}</h3>
            <p>{post.excerpt}</p>
          </li>
        ))}
      </ul>
    </div>
  );
}

Este componente PostList busca a lista de posts de uma API (simulada) e os renderiza. Observe que este componente é assíncrono e pode executar código no servidor.

Agora, vamos criar um componente cliente para atualizar a lista de posts:

// src/components/RefreshButton.tsx
'use client';
 
import { useState } from 'react';
 
export default function RefreshButton({ onRefresh }: { onRefresh: () => void }) {
  const [isRefreshing, setIsRefreshing] = useState(false);
 
  const handleClick = async () => {
    setIsRefreshing(true);
    await onRefresh(); // Chama a função para atualizar os posts
    setIsRefreshing(false);
  };
 
  return (
    <button onClick={handleClick} disabled={isRefreshing}>
      {isRefreshing ? 'Atualizando...' : 'Atualizar Posts'}
    </button>
  );
}

Este componente RefreshButton usa o hook useState para controlar o estado do botão (se está atualizando ou não). Quando o botão é clicado, ele chama a função onRefresh para atualizar a lista de posts.

Finalmente, vamos combinar esses componentes em um componente pai:

// src/app/page.tsx
'use client';
 
import { useState, useCallback } from 'react';
import PostList from '../components/PostList';
import RefreshButton from '../components/RefreshButton';
 
async function getInitialPosts() {
  // Simulate fetching posts on the server
  return [
    { id: 1, title: 'Post 1', excerpt: 'Excerpt 1' },
    { id: 2, title: 'Post 2', excerpt: 'Excerpt 2' },
  ];
}
 
export default function Page() {
  const [posts, setPosts] = useState(async () => await getInitialPosts());
 
  const refreshPosts = useCallback(async () => {
    // Simulate fetching updated posts on the server
    const newPosts = [
      { id: 3, title: 'Post 3 (Updated)', excerpt: 'Excerpt 3' },
      { id: 4, title: 'Post 4 (Updated)', excerpt: 'Excerpt 4' },
    ];
    setPosts(newPosts);
  }, []);
 
  return (
    <div>
      <PostList posts={posts} />
      <RefreshButton onRefresh={refreshPosts} />
    </div>
  );
}

Boas práticas:

  • Separe componentes servidor e cliente: Mantenha seus componentes servidor e cliente em arquivos separados para facilitar a organização e a manutenção do código.
  • Use a diretiva 'use client': Marque explicitamente os componentes cliente com a diretiva 'use client'.
  • Comunique-se através de props: Passe dados entre componentes servidor e cliente através de props serializados.
  • Minimize a hidratação: Tente minimizar a quantidade de componentes que precisam ser hidratados no cliente.
  • Aproveite o streaming: Use o streaming para enviar partes da interface do usuário à medida que elas são renderizadas no servidor.

Armadilhas comuns (gotchas):

  • Acesso direto ao DOM: Você não pode acessar diretamente o DOM em componentes servidor.
  • Hooks em componentes servidor: Você não pode usar hooks do React em componentes servidor.
  • Funções como props: Você não pode passar funções de um componente servidor para um componente cliente diretamente. Você precisa serializar os dados e passá-los como props.
  • Erros de serialização: Certifique-se de que os dados que você está passando entre componentes servidor e cliente podem ser serializados.
  • Confusão entre SSR e RSC: Não confunda Server-Side Rendering (SSR) com React Server Components (RSC). Eles são conceitos diferentes. SSR renderiza a página inteira no servidor, enquanto RSCs permitem renderizar partes da página no servidor.

Vale a Pena?

React Server Components oferecem uma série de benefícios, mas também apresentam algumas limitações. Vamos analisar os prós e contras para determinar se eles valem a pena para o seu projeto.

Prós:

  • Melhoria de Performance: Redução do tamanho do bundle JavaScript, melhoria do FCP e otimização do tempo de carregamento.
  • Acesso Direto ao Backend: Acesso direto a bancos de dados e APIs sem precisar de uma API intermediária.
  • Flexibilidade: Capacidade de renderizar partes da aplicação no servidor e partes no cliente, oferecendo o melhor dos dois mundos.
  • Streaming: Envio de partes da interface do usuário à medida que elas são renderizadas, melhorando a percepção de velocidade.
  • Otimização de Recursos: Redução da carga no cliente, economizando bateria e recursos do dispositivo.

Contras:

  • Complexidade: Introdução de uma nova camada de complexidade à arquitetura da aplicação.
  • Curva de Aprendizagem: Necessidade de aprender novos conceitos e técnicas.
  • Restrições: Limitações no uso de hooks e acesso ao DOM em componentes servidor.
  • Ferramentas e Ecossistema: Ecossistema ainda em desenvolvimento, com menos ferramentas e bibliotecas disponíveis.
  • Debugging: Depuração mais complexa devido à renderização híbrida.

Quando usar vs quando evitar:

Use React Server Components quando:

  • Você precisa melhorar o FCP da sua aplicação.
  • Você tem componentes que precisam acessar dados do backend e não precisam de interatividade no cliente.
  • Você quer reduzir o tamanho do bundle JavaScript da sua aplicação.
  • Você está construindo uma nova aplicação ou está disposto a refatorar uma aplicação existente.

Evite React Server Components quando:

  • Você tem uma aplicação pequena e simples que já tem um bom desempenho.
  • Você não tem tempo ou recursos para aprender novos conceitos e técnicas.
  • Você precisa de acesso direto ao DOM ou de hooks do React em todos os seus componentes.
  • Você não quer introduzir complexidade adicional à sua aplicação.

Performance e DX (Developer Experience):

Os React Server Components podem melhorar significativamente a performance da sua aplicação, mas também podem aumentar a complexidade do desenvolvimento. É importante equilibrar os benefícios de performance com o impacto na DX.

Em termos de performance, os RSCs podem reduzir o tamanho do bundle JavaScript, melhorar o FCP e otimizar o tempo de carregamento. Isso pode levar a uma melhor experiência do usuário e a uma melhor taxa de conversão.

Em termos de DX, os RSCs podem aumentar a complexidade do desenvolvimento, pois exigem que você pense em quais componentes devem ser renderizados no servidor e quais devem ser renderizados no cliente. Eles também introduzem novas restrições no uso de hooks e acesso ao DOM.

Ecossistema e adoção:

O ecossistema dos React Server Components ainda está em desenvolvimento, mas está crescendo rapidamente. Frameworks como Next.js estão integrando os RSCs em suas arquiteturas, facilitando o uso e a adoção.

A adoção dos RSCs ainda é relativamente baixa, mas está aumentando à medida que mais desenvolvedores descobrem os benefícios que eles podem oferecer. Espera-se que a adoção aumente significativamente nos próximos anos à medida que o ecossistema amadurece e mais ferramentas e bibliotecas são desenvolvidas.

Conclusão

Em resumo, os React Server Components são uma poderosa ferramenta para otimizar a performance de aplicações React. Eles permitem renderizar partes da aplicação no servidor, reduzindo o tamanho do bundle JavaScript, melhorando o FCP e simplificando o acesso ao backend.

No entanto, os RSCs também introduzem uma nova camada de complexidade e exigem que você aprenda novos conceitos e técnicas. É importante avaliar cuidadosamente os prós e contras antes de decidir usar RSCs no seu projeto.

Recomendação final:

Se você está construindo uma nova aplicação React ou está disposto a refatorar uma aplicação existente, os React Server Components podem valer a pena o investimento. Eles podem melhorar significativamente a performance da sua aplicação e oferecer uma melhor experiência do usuário.

Se você tem uma aplicação pequena e simples que já tem um bom desempenho, os React Server Components podem não ser necessários.

Próximos passos para o leitor:

  1. Experimente: Comece a experimentar com React Server Components em projetos pequenos e simples para se familiarizar com os conceitos e as técnicas.
  2. Estude: Leia a documentação oficial dos React Server Components e explore tutoriais e exemplos.
  3. Contribua: Participe da comunidade de desenvolvedores de React Server Components e contribua com projetos open source.
  4. Adote: Considere adotar React Server Components em seus projetos maiores e mais complexos para otimizar a performance e melhorar a experiência do usuário.

Recursos

  • Links oficiais de documentação:

    • React Documentation (A documentação oficial do React é o melhor lugar para começar a aprender sobre React Server Components).
    • Next.js Documentation (A documentação do Next.js oferece informações sobre como usar React Server Components em um contexto de framework).
  • Tutoriais adicionais recomendados:

  • Comunidades relacionadas:

    • React Community: Participe da comunidade React para discutir e aprender com outros desenvolvedores.
    • Next.js Community: Participe da comunidade Next.js para obter suporte e compartilhar suas experiências com React Server Components no contexto do Next.js.

Lembre-se de que a adoção de React Server Components é uma jornada. Comece pequeno, aprenda gradualmente e adapte as técnicas às suas necessidades específicas. Boa sorte!

Compartilhe este artigo

Este conteúdo foi útil?

Deixe-nos saber o que achou deste post

Comentários

Deixe um comentário

Carregando comentários...