---
title: "Venir de React"
headingIds:
  [
    "coming-from-react",
    "what-stays-the-same",
    "port-a-presentational-component",
    "what-changes",
    "no-client-runtime-no-hooks",
    "async-is-native-not-suspense",
    "context-and-scope",
    "event-handlers-are-attributes-not-closures",
    "props-that-only-meant-something-to-the-reconciler",
    "migration-checklist",
    "what-you-lose",
    "what-you-gain",
    "next-steps",
  ]
---

# 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.

```tsx
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é.

```tsx
// 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.

```tsx
async function Comments() {
  const data = await fetchComments();
  return <ul>{data.map(/* … */)}</ul>;
}
```

```tsx
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](/fr/api/core/scope).

```tsx
// 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.

```tsx
// 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](/fr/guide/getting-started/installation), les [composants](/fr/guide/jsx/components) et le [streaming](/fr/integration/streaming).
