Ruben Marcus

Feb 25, 2021

7 min read

Um guia de React Server Components

O que é React Server Components?

useEffect(() => {
axios.get("ENDEREÇO AQUI")
.then((response) => {
// set data into state
setData(response.data);
})
.catch((error) => {
console.log(error);
});
}, []);

Como funciona?

"react": "0.0.0-experimental-3310209d0",
"react-dom": "0.0.0-experimental-3310209d0",
"react-fetch": "0.0.0-experimental-3310209d0",
"react-fs": "0.0.0-experimental-3310209d0",
"react-pg": "0.0.0-experimental-3310209d0",
"react-server-dom-webpack": "0.0.0-experimental-3310209d0",
  • .server.js indica um Server Components
  • .client.js indica um React Client Components
  • O habitual .js , pode ser rodado no client ou no server. Dependendo de quem o importa. Também serve para Shared Components. Por exemplo se você importa um Shared Component no server, ele atuará como Server Component, se você importa ele no Client, Será um Client Component.
  • O servidor Node, rodando o scriptserver/api.server.js
  • O build do Webpack rodando o bundle client-side do React, usando o script scripts/build.js
const ReactApp = require('../src/App.server').default;
const {pipeToNodeWritable} = 
require('react-server-dom-webpack/writer');
async function renderReactTree(res, props) {
await waitForWebpack();
const manifest = readFileSync(
path.resolve(__dirname, '../build/react-client-manifest.json'),
'utf8'
);
const moduleMap = JSON.parse(manifest);
pipeToNodeWritable(React.createElement(ReactApp, props), res, moduleMap);
}

Bundle de tamanho Zero

//markdown.jsimport marked from 'marked'; // 37.38KBimport sanitizeHtml from 'sanitize-html'; // 208 KBexport default function TextwithMarkdown({Text}) {
return(
<div className="text-markdown"
dangerousSetInnerHTML={{
__html: sanitizeHtml(marked(text)),
}}
/>
);
}
// markdown.server.jsimport marked from 'marked'; // 0KBimport sanitizeHtml from 'sanitize-html'; // 0KBexport default function TextwithMarkdown({Text}) {
return(
<div className="text-markdown"
dangerousSetInnerHTML={{
__html: sanitizeHtml(marked(text)),
}}
/>
);
}

Acesso do backend ao banco de dados:

export default function NoteList({searchText}) {
const notes = db.query(
`select * from notes where title ilike $1 order by id desc`,
['%' + searchText + '%']
).rows;


return notes.length > 0 ? (
<ul className="notes-list">
{notes.map((note) => (
<li key={note.id}>
<SidebarNote note={note} />
</li>
))}
</ul>
) : (
<div className="notes-empty">
{searchText
? `Couldn't find any notes titled "${searchText}".`
: 'No notes created yet!'}{' '}
</div>
);
}

Restrições

  • Primeiro, um Server Component não tem nenhuma interatividade (sem useState(),nem useEffect()).
    Uma resolução para esse problema, seria importar Client Components, ( que podem ser interativos) , dentro de um Server Component, por exemplo você pode ter o melhor dos dois mundos:
//Page.server.js// import de componente interativo do client
import Button from '.Button.client.js';
export default Page() {
// data fetch, processamento, outras coisas..
return(
// use o <Button /> e outros componentes interativos aqui
);
}
  • Segundo,props de um Server Component para um Client Component tem que ser serializada na rede ( ex: passar dados como strings, JSON e JSX mas não podem passar em funções JavaScript) . Isso é porque os Server Components renderizados tem que ser enviados pela rede.

Rotas

Quais as vantagens?

  • Desenvolvimento mais fácil, por ter acesso a recursos de servidor como : banco de dados,filesystem, micro serviços, etc.).
  • Melhor performance, pois evitamos a latência de rede entre servidor e cliente.
  • Menor tamanho do bundle. Libs que forem usados só no servidor não precisam ser usados no client : (como loadash, rambda, moment,e etc.), além dos Server Components nunca serem incluidos no bundle, e lidos pelo client.
  • Segurança: Fazer queries no lado do servidor sempre é mais seguro que no client. Além de não expor as requisições
  • Pode fazer queries GraphQL
  • Pode acessar diretamente bancos de dados PostgreSQL com o package react-pg
  • Code splitting automático. (A técnica de dividir o código em bundles menores, para o cliente ler apenas o que é necessário) Atualmente, Desenvolvedores React tem que fazer um esforço para poder implementar o code splitting algo como:
const MyComponent = React.lazy(() => import('./MyComponent.js'));
import MyComponent from './MyComponent.client.js';

Como os Server Components são diferentes de SSR (ex: Next.js)?

M1:{"id":"./src/SearchField.client.js","chunks":["client5"],"name":""}

Server Component x Client Components

  1. Assim que você ,uma requisição fetch é feita para uma API para um payload JSON.
  2. Assim que você recebe a resposta, você parseia o JSON, e manda pro React.
  3. O React renderiza os dados, e mostra as informações do filme na tela.
  1. Uma requisição é feita para um backend que você é dono e é capaz de fazer um render RSC ( React Server Component)
  2. O componente é renderizado no próprio servidor, e você recebe um build do markup estático, sem ser JSON ou HTML , como abaixo: M1:{“id”:”./src/SearchField.client.js”,”chunks”:[“client5”],”name”:””}
  3. O frontend (client), renderiza esse markup, como um UI estático ( importante: não um componente React), isso salva processamento adicional do componente no front-end.

Conclusão

Com conteúdo traduzido de:

Links Úteis:

Software Engineer | Front-end Specialist @ Grover (https://rubenmarcus.dev)

Love podcasts or audiobooks? Learn on the go with our new app.