React: O que é React.lazy e React.memo

Introduzidos na versão 16.6 duas boas novidades já disponíveis!

Image for post
Image for post

Apesar da comunidade React estar em hype com React.Hooks. Não podemos esquecer que a versão estável atual introduziu duas novas funcionalidades muito interessantes!

Code-Splitting com React.lazy e Suspense

Em um futuro próximo, será possível fazer data-fetching de uma maneira bem declarativa. Enquanto esse futuro não chega, já é possível utilizar hoje a mesma técnica para criar pontos de divisão em seu código e carregar componentes sob demanda.

Por exemplo:

import * as React from 'react';let Dashboard = React.lazy(() => import("./Dashboard"));function App() {
return (
<div>
<React.Suspense fallback={<div>Carregando...</div>}>
<Dashboard />
</React.Suspense>
</div>
);
}

E o mais legal, é que podemos fazer o mesmo a partir de ações do usuário:

import * as React from "react";class App extends React.Component {
constructor(props) {
super(props);
this.state = {
current: null
};
this.onClickLista = this.onClickLista.bind(this);
}
onClickLista(tipo) { // [A]
let comps = {
ativos: React.lazy(() => import("./ListaAtivos")),
passivos: React.lazy(() => import("./ListaPassivos")),
investimentos: React.lazy(() => import("./ListaInvestimentos"))
};
return e => {
this.setState(state => ({
...state,
current: comps[tipo] || null
}));
};
}
render() {
return (
<div>
<h1>Selecione um item:</h1>
<ul>
<li>
<button onClick={this.onClickLista("ativos")} type="type">
Ativos
</button>
</li>
<li>
<button onClick={this.onClickLista("passivos")} type="type">
Passivos
</button>
</li>
<li>
<button onClick={this.onClickLista("investimentos")} type="type">
Investimentos
</button>
</li>
</ul>
// [B]
{this.state.current !== null && (
<React.Suspense fallback={<div>Carregando...</div>}>
{React.createElement(this.state.current)}
</React.Suspense>
)}
</div>
);
}
}
export default App;
  • [A]: Mapeamos a string passada para a função React.lazy com dynamic import para um componente em nossa pasta local.
  • [B]: Se em nosso estado a chave .current não for null, utilizamos React.Suspense para mostrar um fallback <div>Carregando...</div> enquanto carregamos o componente da etapa [A]. Você pode passar qualquer elemento React para fallback.

UMA REGRA IMPORTANTE: Vale lembrar que, React.lazy espera que o componente seja exportado como valor default. Significa que em nosso ListaAtivo.js precisamos exportar o componente como export default ListaAtivos;.

Caso você não possa ou não queira utilizar export default, você pode mapear o módulo dentro da função do React.lazy:

...
let comps = {
ativos: React.lazy(() =>
import("./ListaAtivos")
.then(comp => {
return {
default: comp.SuperLista
}
})
),
};
...

Dessa maneira, React.Suspense e React.lazy irão funcionar corretamente!

Esqueça PureComponent e utilize React.memo

function Card(props) {
return (
<div>
<p>{props.name}</p>
<p>{props.description}</p>
</div>
)
}

Um "problema" aqui é, se o componente pai for atualizado esse componente irá ser renderizado novamente, mesmo se suas props não mudarem.

E é aqui que entra o PureComponent, onde você iria converter esse componente para:

class Card extends React.PureComponent {
render() {
return (
<div>
<p>{this.props.name}</p>
<p>{this.props.description}</p>
</div>
)
}
}

Resolvendo o problema de re-renderização.

Mas graças ao React.memo, podemos fazer isso utilizando apenas funções:

function Card(props) {
return (
<div>
<p>{props.name}</p>
<p>{props.description}</p>
</div>
)
}
export default React.memo(Card);

Ou, se você preferir arrow function:

let Card = React.memo(props => (
<div>
<p>{props.name}</p>
<p>{props.description}</p>
</div>
))

E qual a vantagem disso? No momento atual temos uma grande discussão entre ES6 Class e Plain Functions (principalmente por causa de React.Hooks), mas não vou entrar nesse mérito.

Uma boa vantagem é que não precisamos refatorar um componente por causa de sua sintaxe.

UMA REGRA IMPORTANTE: Vale lembrar que React.memo não funciona como uma função de memoize, ele aceita APENAS componentes React como primeiro parâmetro. Caso você precise implementar uma função para memoização, temos boas soluções como fast-memoize (do nosso brasileiro Caio Gondim), memoize-one e para soluções mais robustas, a clássica biblioteca reselect.

Finalizando

É um ÓTIMO momento para ser desenvolvedor UI e principalmente, estar trabalhando com React.

Tem alguma dica? Ou uma prática diferente? Compartilhe aí nos comentários!

Written by

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store