# Dokumente und Nodes

> Ein Dokument ist ein Baum aus Komponenten, von denen jede ihre Daten als State nimmt und die Nodes zurückgibt, die sie will.

Source: https://docxcelerate.com/de/docs/essentials/documents-and-nodes/

Ein Dokument ist ein Template plus ein Datentyp. Das Template ist ein Baum aus
**Komponenten**; jede gibt **Nodes** zurück, und den Baum gegen Daten aufzulösen
ergibt ein `DocumentModel` — reines JSON, ohne dass damit ein Rendering gemeint
wäre.

## Eine Komponente nimmt ihre Daten als State

```tsx
import { Paragraph, useState } from "docxcelerate/template";
import type { DocumentData } from "../types.ts";

export const Greeting: Paragraph = () => {
  const [state] = useState((data: DocumentData) => ({
    name: data.residentName,
  }));

  return <Paragraph id="greeting">Dear {state.name},</Paragraph>;
};
```

`useState` ist die Stelle, an der Daten in eine Komponente kommen — und die
einzige. Alles danach liest State. Das ist eine Regel mit einem Grund: Weil jede
Abhängigkeit durch eine einzige Deklaration läuft, steht aufgeschrieben, was
eine Komponente braucht, statt sich über den Code zu verteilen, der es benutzt.

Der Initializer ist gewöhnliches TypeScript. Es gibt keine Template-Sprache,
Bedingungen, Formatierung und Importe stehen also einfach zur Verfügung.

`Paragraph` benennt zugleich das Element und den Komponententyp — ein Wert und
ein Typ dürfen sich einen Namen teilen. `const Greeting: Paragraph` sagt also,
was hier geliefert wird, und ein `<Section>` daraus zurückzugeben ist ein
Compile-Fehler.

## Daten können auch als Props ankommen

Eine Komponente, der man gibt, was sie braucht, muss nicht selbst danach
greifen:

```tsx
export const Arrears: Paragraph<{ amount: number }> = ({ amount }) => {
  const { currency } = useFormat();

  return <Paragraph id="arrears">You owe {currency(amount)}.</Paragraph>;
};
```

Irgendwer muss die Daten zuerst lesen, eine reine Props-Komponente sitzt also
unter einer Eltern-Komponente, die sie in State genommen hat. Nehmen Sie Props
für Komponenten, die Sie gegen verschiedene Werte wiederverwenden wollen, und
State für Komponenten, die wissen, zu welchem Dokument sie gehören.

## Entscheidungen sind ein gewöhnliches `if`

```tsx
export const Balance: Paragraph = () => {
  const [state] = useState((data: DocumentData) => ({
    settled: data.balanceDue === 0,
  }));

  if (state.settled) {
    return <Paragraph id="settled">Nothing outstanding.</Paragraph>;
  }

  return <Paragraph id="arrears">A balance remains.</Paragraph>;
};
```

Geben Sie jedem Zweig eine eigene id. Das aufgelöste Dokument hält dann fest,
welchen dieser Empfänger bekommen hat — und das ist der Unterschied zwischen
einem Dokument, das Sie prüfen können, und einem, das Sie nur ansehen können.

Zum Verzweigen gibt es eine Sache zu wissen, bevor Sie an eine Engine
veröffentlichen: siehe [was sich beim
Veröffentlichen ändert](/de/docs/essentials/templates/#was-sich-beim-veröffentlichen-ändert).

## Ids

Eine id ist die Adresse, unter der eine Engine einen Node anspricht und unter
der Build-Artefakte zwischen Läufen diffbar bleiben. Behandeln Sie eine
Umbenennung als Breaking Change.

Sie dürfen sie weglassen. Ein Node ohne id bekommt eine aus seiner Position, und
genau das verhindert, dass Verzweigungen und Schleifen Sie zwingen, Namen zu
erfinden. Was nicht geht, ist dieselbe zweimal: Zwei Nodes, die eine id
beanspruchen, sind ein Fehler — gemeldet mit beiden Positionen — und kein
Wettlauf, den der spätere gewinnt.

## Sections verschachteln, Nodes nicht

`Section` ist die einzige verschachtelnde Konstruktion. Ihr Titel trägt in die
Gliederung des Dokuments:

```tsx
<Section id="opening" title="Opening">
  <Greeting />
  <Offer />
</Section>
```

Siehe [Section](/de/docs/nodes/section/) dafür, was eine Section enthalten darf
und wie tief.

## Hooks

Hooks sind der Weg, auf dem eine Komponente den Build um sich herum erreicht:

| Hook | Was er Ihnen gibt |
| --- | --- |
| `useState` | Daten, einmal hereingenommen und behalten |
| `useShared` | Ein Wert für die Komponenten, die danach gerendert werden |
| `useSetPrompts` | Prompts für den gelieferten Node — was ihn dynamisch macht |
| `useSetPlaceholders` | Was Vorschauen statt erzeugter Inhalte zeigen |
| `usePlaceholderData` | Ersatz-Namen, -Daten und -Zahlen für Vorschauen |
| `useFormat` | Sprachraumgerechte Währungen, Daten, Listen und Pluralformen |
| `useAvailableTokens` | Das Token-Budget, das dieser Build zugeteilt hat |
| `useDeriver` | Führt einen registrierten Deriver jetzt aus |

Sie laufen in Aufrufreihenfolge, jeder Hook muss also vor dem ersten `await` und
vor jeder Verzweigung erreicht werden — dieselbe Regel wie in React, aus
demselben Grund. Einen nach einem `await` aufzurufen ist ein Fehler, der das
auch sagt, statt sich still an die nächste gerenderte Komponente zu hängen.

## Das Dokument bauen

```ts
import { buildDocument } from "docxcelerate";

const doc = await buildDocument(documentTemplate, data);
```

Das Ergebnis ist ein `DocumentModel`: eine `schemaVersion`, eine `id`, ein
`title` und ein `nodes`-Array. Es enthält kein Styling und kein Layout — die
kommen später von dem Renderer, der es konsumiert.

Für ein mit `defineDocumentProject` definiertes Dokumentprojekt nehmen Sie
besser `buildProjectPreviewDocument`: Es wendet den Stil des Projekts an und
löst dynamische Nodes zu ihren Platzhaltern auf:

```ts
import { buildProjectPreviewDocument } from "docxcelerate";

const doc = await buildProjectPreviewDocument(project);
```

Genau das ruft die Vorschau-App auf, was Sie im Code bauen entspricht also dem,
was Sie im Browser gesehen haben.
