Skip to content
Vincle

Loading…

    Components

    A component is a plain function: props in, JSX out. No classes, no hooks, no lifecycle.

    Basics#

    import { renderToString } from "@vincle/core";
    function Greeting({ name }: { name: string }) {
    return (
    <p>
    Hello, <strong>{name}</strong>!
    </p>
    );
    }
    const html = await renderToString(<Greeting name="Alice" />);
    <p>Hello, <strong>Alice</strong>!</p>

    Typed props and composition#

    Props are typed with ordinary TypeScript. Children arrive in the children prop, so one component's output becomes another's content:

    import { renderToString, type JSX } from "@vincle/core";
    function Layout({ title, children }: { title: string; children: JSX.Element | JSX.Element[] }) {
    return (
    <html lang="en">
    <head>
    <title>{title}</title>
    </head>
    <body>{children}</body>
    </html>
    );
    }
    const html = await renderToString(
    <Layout title="My page">
    <h1>Welcome</h1>
    <p>This is a page rendered with Vincle.</p>
    </Layout>,
    );

    Async components#

    Any component can be async. renderToString awaits the whole tree:

    async function Profile({ id }: { id: string }) {
    const user = await db.users.find(id);
    return (
    <div class="profile">
    <h1>{user.name}</h1>
    <p>{user.bio}</p>
    </div>
    );
    }

    Sibling async branches run in document order, one at a time.

    What you don't need#

    A render calls each component once and produces a string. Nothing re-renders, so there is no state (it lives outside the render: database, request context), no effects, and no React.memo. A Context.Provider supplies values during the server render only.

    Where to next#