Aller au contenu
Vincle

Chargement…

    Venir de React

    La syntaxe JSX vous sera familière. Vincle rend du HTML sur le serveur ; il n’exécute pas un arbre React dans le navigateur.

    Ce qui reste identique#

    Conservez les fonctions de composants, les props typées, la composition, les conditions et les listes JSX.

    Porter un composant de présentation#

    Un composant de présentation peut souvent être adapté en changeant le runtime JSX et les types. Remplacez les attributs ou comportements propres au client lorsqu’ils n’ont pas de sens dans une chaîne HTML.

    import type { Renderable } from "@vincle/core";
    type CardProps = { title: string; children?: Renderable };
    export function Card({ title, children }: CardProps) {
    return (
    <section className="card">
    <h2>{title}</h2>
    {children}
    </section>
    );
    }

    Ce qui change#

    Les différences concernent le cycle de vie, les effets client et le moment où les données sont chargées.

    Aucun runtime client ni hook#

    Aucun useState, useEffect ou hydratation n’est fourni. Utilisez votre JavaScript client ou une intégration telle que HTMX ou Turbo pour l’interactivité.

    // React: "use client", and React + ReactDOM shipped to run one counter
    "use client";
    export function Counter() {
    const [count, setCount] = useState(0);
    return <button onClick={() => setCount((c) => c + 1)}>{count}</button>;
    }
    // Vincle: renders once; Alpine.js does the counting in the browser
    export function Counter() {
    return (
    <div x-data="{ count: 0 }">
    <button x-on:click="count++" x-text="count">
    0
    </button>
    </div>
    );
    }

    L’asynchrone avec des fonctions ordinaires#

    Les composants async attendent directement les données. <Defer> dans Flow décrit explicitement les régions livrées plus tard ; il ne repose pas sur Suspense.

    async function Comments() {
    const data = await fetchComments();
    return <ul>{data.map(/* … */)}</ul>;
    }
    import { Defer } from "@vincle/flow";
    function Page() {
    return (
    <Defer target="comments" fallback={<Spinner />} timeout={5000}>
    <Comments />
    </Defer>
    );
    }

    Contexte et Scope#

    createContext et les Providers transmettent des valeurs dans un sous-arbre. Scope fournit des clés mutables propres à une exécution. Consultez les règles d’isolation des contextes.

    // Descendants read the nearest Provider.
    const Auth = createContext({ user: { name: "Guest" } });
    function Page() {
    return <li>{useContext(Auth).user.name}</li>;
    }
    await renderToString(
    <Auth.Provider value={{ user }}>
    <Page />
    </Auth.Provider>,
    );
    // Mutable execution state, readable from a plain helper.
    const Audit = Scope.key<{ user: { name: string } }>("app:audit");
    function logAction(action: string) {
    const { user } = Scope.get(Audit);
    console.log(`${user.name}: ${action}`);
    }
    await Scope.with(() => {
    Scope.set(Audit, { user });
    logAction("viewed dashboard");
    return renderToString(<Page />);
    });

    Les événements sont des attributs, pas des fermetures#

    Un attribut d’événement représente du code HTML sous forme de chaîne. Une fermeture JavaScript ne peut pas être transportée dans le document produit. Préférez des scripts dédiés ou des attributs d’intégration.

    // React: the closure needs the component, and its runtime, in the loop
    const onDelete = useCallback(() => handleDelete(id), [id]);
    <DeleteButton onClick={onDelete}>Delete</DeleteButton>;
    // Vincle: a standard HTML form. Forms only support GET and POST natively,
    // so DELETE is a route, not a verb.
    <form action={`/items/${id}/delete`} method="POST">
    <button type="submit">Delete</button>
    </form>;
    // Vincle + HTMX: HTMX reads the attributes, issues the request, swaps the response.
    <button hx-delete={`/api/items/${id}`} hx-target="#item-list" hx-swap="outerHTML">
    Delete
    </button>;

    Props spécifiques au système de réconciliation#

    Les props destinées à la réconciliation ou au runtime React n’ont pas le même rôle ici. Vérifiez les refs, les clés, les valeurs contrôlées et les effets lors du portage.

    Étapes de migration#

    Changez le runtime JSX, adaptez les types, retirez les hooks client, chargez les données côté serveur, remplacez les callbacks d’événement et testez le HTML ainsi que les chemins raw().

    Ce que vous perdez#

    Vous perdez le runtime React client, son système d’état et son écosystème de composants dépendant de hooks ou du DOM. Ces composants ne sont pas directement utilisables comme composants Vincle.

    Ce que vous gagnez#

    Vous gagnez un rendu serveur simple, des composants asynchrones ordinaires et un document sans coût d’hydratation. Flow ajoute les mises à jour progressives lorsque vous en avez besoin.

    Étapes suivantes#

    Consultez l’installation, les composants et le streaming.