Remix.run e a nova geração de frameworks para desenvolvimento web


vedovelli74

Os tipos de arquitetura web
MPA
SPA

O PROBLEMA
SPAs se tornaram MUITO complexas
- Gerenciamento de estado em 2 locais
- Invalidação dos dados no client
- Páginas pesadas devido ao excesso de JS
- Projetos difíceis de compreender
- Muitas chamadas AJAX



















Como o Remix resolve os problemas?
Usemos o próprio site da ferramenta como guia!
Rotas e rotas aninhadas (nested)
"São unidades independentes e capazes de suprir todas as necessidades daquele pedaço da funcionalidade"
Rotas e rotas aninhadas (nested)
"Quando uma rota aninhada é acessada, os dados da rota pai NÃO SÃO obtidos novamente"
Rotas e rotas aninhadas (nested)
"Remix provê padrões claros que determinam onde e em qual momento uma ação deve ser feita"
export const loader = async ({request}: LoaderArgs) => {
// DATA FETCH
}
export const action = async ({request}: ActionArgs) => {
// DATA SAVE
}
export default function ReactComponent() {
const loaderData = useLoaderData<typeof loader>()
const actionData = useActionData<typeof action>()
return (
<form method="POST">...</form>
);
}
export function ErrorBoundary({error}: {error: Error}) {
return (
<>...</>
);
}
export function CatchBoundary() {
return (
<>...</>
);
}
export const meta = () => ({
title: 'My Page',
})
export const links = () => ({
stylesheet: MyStylesheet,
})
Rotas e rotas aninhadas (nested)
"Em resumo, podemos pensar nas rotas com CONTROLLERS e nos componentes React como VIEWS.
Já os models o Remix deixa por sua conta."
Melhoria progressiva (progressive enhancement)
Remix possui uma estratégia sólida para receber, validar, tratar e salvar dados providos pelo usuário.
Use um <form>
export default function () {
const [name, setName] = React.useState();
const [email, setEmail] = React.useState();
const [error, setError] = React.useState();
const onSubmit = (event) => {
event.preventDefault(); // TIRE O BROWSER DE CENA E ASSUMA VOCÊ O CONTROLE DA SITUAÇÃO! 💪🏻
// Validação dos dados, talvez?
try {
// Tudo certo, enviar para nossa API
await UserApi.createUser({ name, email });
// Não se esqueça de limpar o form 🧹
} catch (error) {
setError(error.message);
}
};
return (
<form onSubmit={onSubmit}>
<input
type="text"
value={name}
onChange={(event) => setName(event.target.value)}
/>
...
</form>
);
}
Como fazemos hoje:
export const action = async ({ request }) => {
const data = Object.fromEntries(await request.formData());
// Validar antes de salvar, claro! 🤓
try {
return await UserApi.createUser({ name: data.name, email: data.email });
} catch (error) {
throw new Error('whoopsie...')
}
};
export default function () {
const data = useActionData()
return (
<form method="post">
<input type="text" name="name" />
<input type="email" name="email" />
<button type="submit">Salvar</button>
</form>
);
}
export function ErrorBoundary() {
return <h1>Whoops!</h1>;
}
Como fazemos com Remix:
🌈🦄
<Form
method="post"
schema={schema}
mode="onChange"
// See /styles/tailwind.css for `signup-form`
className={cx("signup-form", className)}
>
{({ Field, Errors, register, formState: { dirtyFields, isValid } }) => (
<>
<Field
name="fullLegalNameAtBirth"
label={`${txt!["full_legal_name_at_birth"]} *`}
>
{({ Label, errors }) => (
<Fieldset>
<legend className="px-2">
<Label className="w-40 antialiased font-semibold text-softgreen" />
</legend>
<UserIcon className="w-8 h-8 text-lightgray" />
<input
{...register("fullLegalNameAtBirth")}
required
type="text"
className="w-full px-4 py-2 bg-transparent outline-none"
autoFocus
/>
{errors ? (
<XCircleIcon className="text-red-600 w-9 h-9" />
) : null}
{dirtyFields["fullLegalNameAtBirth"] && !errors ? (
<CheckCircleIcon className="text-softgreen w-9 h-9" />
) : null}
</Fieldset>
)}
</Field>
...
👹
export const action = async ({ request }) => {
const data = Object.fromEntries(await request.formData());
// Validar antes de salvar, claro! 🤓
try {
return await UserApi.createUser({ name: data.name, email: data.email });
} catch (error) {
thow new Error('whoopsie...')
}
};
export default function () {
const data = useActionData()
const transition = useTransition()
return (
<Form method="post">
<input type="text" name="name" />
<input type="email" name="email" />
<button type="submit">{transition.state === 'submitting' ? 'Salvando':'Salvar'}</button>
</Form>
);
}
export function ErrorBoundary() {
return <h1>Whoops!</h1>;
}
Progressive Enhancement
🌈🦄
Melhoria progressiva (progressive enhancement)
"Neste caso você só precisa limpar o form.
O Remix executará o loader após executar a action e seus dados estarão atualizados.
Sem sua interferência!"
Melhoria progressiva (progressive enhancement)
"Curiosidade: o que acontece se o Javascript estiver desabilitado no browser?"
O Remix utilizará a versão padrão, ou seja, sem AJAX.
Developer Experience - DX
- Clara separação do que é executado no server e no client
- A maioria é executada no server (+ segurança)
- Se escreve uma quantidade menor de código
- Pouca mudança de contexto
- Trabalha com os padrões web
- Excelente documentação e tutoriais
- Pacotes de qualidade, por ex. Remix-Forms ♥️
Qualidade da aplicação
- Aplicações mais sólidas
- E mais rápidas:
- Menor JS bundle size
- Menor trabalho para o browser
- Edge Network
- SEO

“É a melhor ponte entre server side e o browser.
Uma revolução comparável ao lançamento do Rails.”
GUGA GUICHARD


Tudo muito bonito, mas me
conta: quem usa o Remix?
Tem alguém forte usando?"
Tudo muito bonito, mas me
conta: quem usa o Remix?
Tem alguém forte usando?"

Recursos

bit.ly/ved-remix
Recursos
remix.run/docs
Recursos
remix.guide
bit.ly/kent-remix

bit.ly/ved-js-tests
cupom: FRONTINFLORIPA
50% de desconto, apenas hoje!
Remix.run 2023
By Fabio Vedovelli
Remix.run 2023
- 609