Migrar desde React

Carats está deliberadamente cerca de React, así que la mayor parte del código de los componentes se porta directamente. Las diferencias de abajo son las que realmente rompen un port.

ConceptoReactCarats
Entorno de ejecuciónReact, React DOM y un DOM virtualSolo JJSX; los componentes son funciones que devuelven HTML
EstadouseState vuelve a renderizar el componenteuse guarda un valor; el DOM se actualiza a mano
EfectosuseEffect con un array de dependenciasafterMount (tras la carga) o beforeMount (inmediato), sin dependencias
Manejadores de eventos<button onClick={fn}>addEventListener dentro de una llamada de hook
EnrutamientoUn enrutador de sistema de archivos con diseños y rutas anidadasUn mapa de defineFacets, compuesto importando un diseño
Datos del servidorgetServerSideProps en la páginaUn culet por ruta más un envoltorio Burnish
Cabecera del documentonext/head o la exportación de metadatos del frameworkthis.head dentro de un componente de función
Metadatos del componenteComponent.displayName, memo y contextdefaultProps en el componente; sin context ni memo
EstilosCSS-in-JS o clases utilitariasSASS con alcance que importa tokens de diseño compartidos
TiposInterfaces importadas por archivoInterfaces DTO globales desde src/dto

Manejadores de eventos

El modelo de eventos es el cambio que más a menudo rompe una migración, así que conviene ser preciso con él.

// React
<button onClick={() => setOpen(!open)}>Toggle</button>
<input value={query} onChange={(e) => setQuery(e.target.value)} />
// Carats
import { use, afterMount } from '@carats/hooks';

export default function Toggle() {
    const open = use(false);

    afterMount(() => {
        const button = document.getElementById('toggle');

        const stop = open.subscribe((value) => {
            button?.setAttribute('aria-expanded', String(value));
        });

        const onClick = () => open.set(!open.get());
        button?.addEventListener('click', onClick);

        return () => {
            stop();
            button?.removeEventListener('click', onClick);
        };
    });

    return <button id="toggle" aria-expanded="false">Toggle</button>;
}

Estado

useState pasa a ser use, y cada renderizado que React se habría encargado se convierte en una escritura explícita del DOM. El estado que era local a un componente no cambia en esencia: llama a use en el nivel superior del componente, léelo con get y escríbelo con set.

Enrutamiento

El enrutador del sistema de archivos se colapsa en un único objeto. Cada ruta se convierte en una entrada de defineFacets, y los diseños anidados se convierten en un import explícito. Como el objeto de facetas es compartido, una ruta que falte en él falta tanto en el cliente como en el servidor, lo que elimina toda una clase de errores.

Datos del servidor

getServerSideProps pasa a ser un culet, y la página pasa a estar bruñida. La firma de la función mantiene la misma forma: entra la petición, salen los datos.

// React / Next.js
export async function getServerSideProps({ params }) {
    return { props: { symbol: params.symbol } };
}
// Carats
export default culet<TradeData>('/trade/:symbol', async (req) => {
    return { symbol: req.params.symbol.toUpperCase() };
});
// Carats page
export default Burnish<TradeData>(function (data) {
    return <h1>{data.symbol}</h1>;
});

Cabecera del documento

Una exportación de metadatos pasa a ser this.head, y el componente tiene que ser una declaración function para que exista this. Un componente que ya es una función de flecha puede seguir siéndolo, a costa de no aportar etiquetas head.

Estilos

CSS-in-JS no tiene equivalente. Cada componente importa un archivo SASS, ese archivo importa base.sass para los tokens de diseño, y los tokens viven en el nivel superior de esa única hoja de estilos global.

Lista de comprobación de la migración

  1. Borra react, react-dom y todas las dependencias que solo usen React.
  2. Sustituye los atributos de evento por addEventListener dentro de una llamada afterMount o beforeMount.
  3. Convierte cada ruta basada en archivos en una entrada del mapa de facetas, e importa un diseño compartido de forma explícita.
  4. Mueve el cuerpo de getServerSideProps a los culets y envuelve la página con Burnish.
  5. Mueve useState a use y añade la actualización manual del DOM que hacía el rerenderizado.
  6. Mueve la exportación head a this.head en un componente de función.
  7. Sustituye CSS-in-JS por archivos SASS que importa cada componente.