Next com SSR - Como renderizar a página antes da api ser chamada
Um dos grandes problemas que tive quando estava começando a usar o Next.js era como melhorar o tempo de carregamento da página utilizando o Server Side Rendering, pois demorava tanto que o Vercel sempre dava timeout no meu site.
O problema
Por algum motivo, a página demorava muito para carregar, mesmo quando eu retornava uma propriedade estática diretamente do getServerSideProps.
A pesquisa
Quando se tem um problema do qual não se tem conhecimento, é preciso saber o que pesquisar para receber uma resposta válida, principalmente quando é um problema pouco explorado. Então, me pus a procurar em vários sites, tanto na documentação, quanto no stack overflow e afins. Vou listar aqui algumas das soluções:
Importar apenas o componente específico
Normalmente utilizamos:
import { input, Box, Typography } from '@mui/material'
Porém esse import carrega toda a pasta @mui/material na página e não apenas os componentes especificados, logo, é recomendado utilizar:
import Input from '@mui/material/Input';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
Concordo que é meio contraintuitivo, principalmente para iniciantes, mas nem sempre escrever menos código é a melhor escolha, principalmente quando se trabalha em grupo. Além disso, nem sempre é possível importar apenas o componente específico.
Carregar dinamicamente os imports e imagens da página
Aos utilizarmos os imports, todos eles são carregados na página de uma vez, mesmo que ele não seja utilizado ou esteja visível. Para adicionar um pouco mais de velocidade no carregamento da página, podemos utilizar o hook dynamic.
Vamos considerar que o component ProfileImage
só é mostrado quando um certo botão é clicado. Invés de importar desta forma:
import ProfileImage from '../components/ProfileImage'
Podemos utilizar o dynamic que é fornecido pelo Next para importarmos dinamicamente nosso componente:
import dynamic from "next/dynamic";
const ProfileImage = dynamic( import("../components/ProfileImage") )
O hook também pode ser personalizado de várias formas, sendo uma delas:
const ProfileImage = dynamic(() => import("../components/ProfileImage"), {
loading: <LoaderComponent />
})
Carregar a página antes de finalizar o getServerSideProps
Essa foi a que fez mais efeito no meu código, ele basicamente renderiza a página antes do getServerSideProps ser finalizado e após a conclusão, a página renderizada novamente com os novos dados.
Utilizando a propriedade req
, que nos é dada pelo próprio Next, é possível fazer isso. Para facilitar o entendimento, utilizarei Typescript para o exemplo, e consideraremos useFetch um hook personalizado que nos retorna [data, loading]
:
import { GetServerSideProps } from 'next';
...
const isServerReq = (req: any) => !req.url.startsWith('/_next');
...
export const getServerSideProps: GetServerSideProps = async ({ req }) => {
const fetchResponse = isServerReq(req) ? await useFetch(some_url) : [null, true];
const [data, loading] = fetchResponse;
return {
props: {
data,
loading
}
}
}
De maneira simples, a função isServerReq verifica se já foi carregado via SSR, caso não, é como se o SSR fosse desabilitado temporariamente e ligado novamente após a conclusão do carregamento. Link para mais informações: https://github.com/vercel/next.js/issues/13910
Problema resolvido
Graças ao último tópico, consegui fazer meu deploy no Vercel funcionar, mas não é a maneira recomendada de utilizar, porém, caso queiram saber mais sobre otimização irei deixar alguns links como fonte desse artigo.