Grundlagen lernen

Diese Anleitung hilft Ihnen, die Grundlagen von TanStack Start zu erlernen, unabhängig davon, wie Sie Ihr Projekt eingerichtet haben.

Abhängigkeiten

TanStack Start wird von Vite und TanStack Router angetrieben.

  • TanStack Router: Ein Router zum Erstellen von Webanwendungen.
  • Vite: Ein Build-Tool zum Bündeln Ihrer Anwendung.

Alles "beginnt" mit dem Router

Dies ist die Datei, die das Verhalten des in Start verwendeten TanStack Routers bestimmt. Hier können Sie alles konfigurieren, von der Standard- Preloading-Funktionalität bis zur Staleness von Caches.

tsx
// app/router.tsx
import { createRouter as createTanStackRouter } from '@tanstack/solid-router'
import { routeTree } from './routeTree.gen'

export function createRouter() {
  const router = createTanStackRouter({
    routeTree,
    scrollRestoration: true,
  })

  return router
}

declare module '@tanstack/solid-router' {
  interface Register {
    router: ReturnType<typeof createRouter>
  }
}
// app/router.tsx
import { createRouter as createTanStackRouter } from '@tanstack/solid-router'
import { routeTree } from './routeTree.gen'

export function createRouter() {
  const router = createTanStackRouter({
    routeTree,
    scrollRestoration: true,
  })

  return router
}

declare module '@tanstack/solid-router' {
  interface Register {
    router: ReturnType<typeof createRouter>
  }
}
  • Beachten Sie die Eigenschaft scrollRestoration. Diese wird verwendet, um die Scrollposition der Seite bei der Navigation zwischen Routen wiederherzustellen.

Routengenerierung

Die Datei routeTree.gen.ts wird generiert, wenn Sie TanStack Start (über npm run dev oder npm run start) zum ersten Mal ausführen. Diese Datei enthält den generierten Routenbaum und einige TS-Utilities, die TanStack Start vollständig typsicher machen.

Der serverseitige Einstiegspunkt (optional)

Hinweis

Der serverseitige Einstiegspunkt ist standardmäßig optional. Wenn er nicht bereitgestellt wird, übernimmt TanStack Start den serverseitigen Einstiegspunkt automatisch für Sie, indem er den folgenden als Standard verwendet.

Dies geschieht über die Datei src/server.ts

tsx
// src/server.ts
import {
  createStartHandler,
  defaultStreamHandler,
} from '@tanstack/solid-start/server'

import { createRouter } from './router'

export default createStartHandler({
  createRouter,
})(defaultStreamHandler)
// src/server.ts
import {
  createStartHandler,
  defaultStreamHandler,
} from '@tanstack/solid-start/server'

import { createRouter } from './router'

export default createStartHandler({
  createRouter,
})(defaultStreamHandler)

Unabhängig davon, ob wir unsere App statisch generieren oder dynamisch ausliefern, ist die Datei server.ts der Einstiegspunkt für alle SSR-bezogenen Arbeiten.

  • Es ist wichtig, dass für jede Anfrage ein neuer Router erstellt wird. Dies stellt sicher, dass alle vom Router verarbeiteten Daten für die jeweilige Anfrage eindeutig sind.
  • Die Funktion defaultStreamHandler wird verwendet, um unsere Anwendung in einen Stream zu rendern, wodurch wir die Vorteile von Streaming-HTML zum Client nutzen können. (Dies ist der Standardhandler, aber Sie können auch andere Handler wie defaultRenderHandler verwenden oder sogar eigene erstellen.)

Der clientseitige Einstiegspunkt (optional)

Hinweis

Der clientseitige Einstiegspunkt ist standardmäßig optional. Wenn er nicht bereitgestellt wird, übernimmt TanStack Start den clientseitigen Einstiegspunkt automatisch für Sie, indem er den folgenden als Standard verwendet.

Unser HTML zum Client zu bringen ist nur die halbe Miete. Sobald es dort ist, müssen wir unser clientseitiges JavaScript hydrieren, sobald die Route zum Client aufgelöst wurde. Dies tun wir, indem wir die Wurzel unserer Anwendung mit der Komponente StartClient hydrieren.

tsx
// app/client.tsx
import { hydrate } from 'solid-js/web'
import { StartClient } from '@tanstack/solid-start'
import { createRouter } from './router'

const router = createRouter()

hydrate(() => <StartClient router={router} />, document)
// app/client.tsx
import { hydrate } from 'solid-js/web'
import { StartClient } from '@tanstack/solid-start'
import { createRouter } from './router'

const router = createRouter()

hydrate(() => <StartClient router={router} />, document)

Dies ermöglicht es uns, die clientseitige Weiterleitung zu starten, sobald die anfängliche Serveranfrage des Benutzers abgeschlossen ist.

Die Wurzel Ihrer Anwendung

Abgesehen vom clientseitigen Einstiegspunkt (der standardmäßig optional ist), ist die Route __root Ihrer Anwendung der Einstiegspunkt. Der Code in dieser Datei umschließt alle anderen Routen in der App, einschließlich Ihrer Startseite. Sie verhält sich wie eine pfadlose Layout-Route für Ihre gesamte Anwendung.

Da sie immer gerendert wird, ist sie der perfekte Ort, um Ihre Anwendungsoberfläche zu erstellen und globale Logik zu handhaben.

tsx
// app/routes/__root.tsx
import {
  Outlet,
  createRootRoute,
  HeadContent,
  Scripts,
} from '@tanstack/solid-router'

export const Route = createRootRoute({
  head: () => ({
    meta: [
      {
        charSet: 'utf-8',
      },
      {
        name: 'viewport',
        content: 'width=device-width, initial-scale=1',
      },
      {
        title: 'TanStack Start Starter',
      },
    ],
  }),
  component: RootComponent,
})

function RootComponent() {
  return <Outlet />
}
// app/routes/__root.tsx
import {
  Outlet,
  createRootRoute,
  HeadContent,
  Scripts,
} from '@tanstack/solid-router'

export const Route = createRootRoute({
  head: () => ({
    meta: [
      {
        charSet: 'utf-8',
      },
      {
        name: 'viewport',
        content: 'width=device-width, initial-scale=1',
      },
      {
        title: 'TanStack Start Starter',
      },
    ],
  }),
  component: RootComponent,
})

function RootComponent() {
  return <Outlet />
}
  • Dieses Layout kann sich in Zukunft ändern, wenn wir den SPA-Modus einführen, der es der Root-Route ermöglicht, die SPA-Oberfläche ohne seitenbezogenen Inhalt zu rendern.
  • Beachten Sie die Komponente Scripts. Diese wird verwendet, um das gesamte clientseitige JavaScript für die Anwendung zu laden.

Routen

Routen sind ein umfangreiches Feature von TanStack Router und werden im Routing-Leitfaden ausführlich behandelt. Zusammenfassend lässt sich sagen:

  • Routen werden mit der Funktion createFileRoute definiert.
  • Routen werden automatisch per Code-Splitting aufgeteilt und per Lazy-Loading geladen.
  • Wichtige Datenabrufe werden von einem Lader einer Route koordiniert.
  • Vieles mehr!
tsx
// app/routes/index.tsx
import * as fs from 'node:fs'
import { createFileRoute, useRouter } from '@tanstack/solid-router'
import { createServerFn } from '@tanstack/solid-start'

const filePath = 'count.txt'

async function readCount() {
  return parseInt(
    await fs.promises.readFile(filePath, 'utf-8').catch(() => '0'),
  )
}

const getCount = createServerFn({
  method: 'GET',
}).handler(() => {
  return readCount()
})

const updateCount = createServerFn({ method: 'POST' })
  .validator((d: number) => d)
  .handler(async ({ data }) => {
    const count = await readCount()
    await fs.promises.writeFile(filePath, `${count + data}`)
  })

export const Route = createFileRoute('/')({
  component: Home,
  loader: async () => await getCount(),
})

function Home() {
  const router = useRouter()
  const state = Route.useLoaderData()

  return (
    <button
      type="button"
      onClick={() => {
        updateCount({ data: 1 }).then(() => {
          router.invalidate()
        })
      }}
    >
      Add 1 to {state}?
    </button>
  )
}
// app/routes/index.tsx
import * as fs from 'node:fs'
import { createFileRoute, useRouter } from '@tanstack/solid-router'
import { createServerFn } from '@tanstack/solid-start'

const filePath = 'count.txt'

async function readCount() {
  return parseInt(
    await fs.promises.readFile(filePath, 'utf-8').catch(() => '0'),
  )
}

const getCount = createServerFn({
  method: 'GET',
}).handler(() => {
  return readCount()
})

const updateCount = createServerFn({ method: 'POST' })
  .validator((d: number) => d)
  .handler(async ({ data }) => {
    const count = await readCount()
    await fs.promises.writeFile(filePath, `${count + data}`)
  })

export const Route = createFileRoute('/')({
  component: Home,
  loader: async () => await getCount(),
})

function Home() {
  const router = useRouter()
  const state = Route.useLoaderData()

  return (
    <button
      type="button"
      onClick={() => {
        updateCount({ data: 1 }).then(() => {
          router.invalidate()
        })
      }}
    >
      Add 1 to {state}?
    </button>
  )
}

TanStack Start baut zu 100 % auf TanStack Router auf, sodass Ihnen alle Navigationsfunktionen von TanStack Router zur Verfügung stehen. Zusammenfassend:

  • Verwenden Sie die Komponente Link, um zu einer neuen Route zu navigieren.
  • Verwenden Sie den Hook useNavigate, um imperativ zu navigieren.
  • Verwenden Sie den Hook useRouter überall in Ihrer Anwendung, um auf die Router-Instanz zuzugreifen und Invalidierungen durchzuführen.
  • Jeder Router-Hook, der einen Zustand zurückgibt, ist reaktiv, was bedeutet, dass er automatisch neu ausgeführt wird, wenn sich der entsprechende Zustand ändert.

Hier ist ein kurzes Beispiel, wie Sie die Komponente Link verwenden können, um zu einer neuen Route zu navigieren.

tsx
import { Link } from '@tanstack/solid-router'

function Home() {
  return <Link to="/about">About</Link>
}
import { Link } from '@tanstack/solid-router'

function Home() {
  return <Link to="/about">About</Link>
}

Weitere detaillierte Informationen zur Navigation finden Sie im Navigationsleitfaden.

Serverfunktionen (RPCs)

Sie haben vielleicht die Serverfunktion bemerkt, die wir oben mit createServerFn erstellt haben. Dies ist eine der leistungsstärksten Funktionen von TanStack, mit der Sie serverseitige Funktionen erstellen können, die sowohl vom Server während SSR als auch vom Client aufgerufen werden können!

Hier ist ein kurzer Überblick, wie Serverfunktionen funktionieren.

  • Serverfunktionen werden mit der Funktion createServerFn erstellt.
  • Sie können sowohl vom Server während SSR als auch vom Client aufgerufen werden.
  • Sie können verwendet werden, um Daten vom Server abzurufen oder andere serverseitige Aktionen auszuführen.

Hier ist ein kurzes Beispiel, wie Sie Serverfunktionen verwenden können, um Daten vom Server abzurufen und zurückzugeben.

tsx
import { createServerFn } from '@tanstack/solid-start'
import * as fs from 'node:fs'
import { z } from 'zod'

const getUserById = createServerFn({ method: 'GET' })
  // Always validate data sent to the function, here we use Zod
  .validator(z.string())
  // The handler function is where you perform the server-side logic
  .handler(async ({ data }) => {
    return db.query.users.findFirst({ where: eq(users.id, data) })
  })

// Somewhere else in your application
const user = await getUserById({ data: '1' })
import { createServerFn } from '@tanstack/solid-start'
import * as fs from 'node:fs'
import { z } from 'zod'

const getUserById = createServerFn({ method: 'GET' })
  // Always validate data sent to the function, here we use Zod
  .validator(z.string())
  // The handler function is where you perform the server-side logic
  .handler(async ({ data }) => {
    return db.query.users.findFirst({ where: eq(users.id, data) })
  })

// Somewhere else in your application
const user = await getUserById({ data: '1' })

Um mehr über Serverfunktionen zu erfahren, besuchen Sie den Serverfunktionen-Leitfaden.

Mutationen

Serverfunktionen können auch verwendet werden, um Mutationen auf dem Server durchzuführen. Dies geschieht ebenfalls mit der gleichen Funktion createServerFn, jedoch mit der zusätzlichen Anforderung, dass Sie alle Daten auf dem Client invalidieren, die von der Mutation betroffen waren.

  • Wenn Sie nur TanStack Router verwenden, können Sie die Methode router.invalidate() verwenden, um alle Router-Daten zu invalidieren und neu abzurufen.
  • Wenn Sie TanStack Query verwenden, können Sie die Methode queryClient.invalidateQueries() verwenden, um Daten zu invalidieren, sowie andere spezifischere Methoden, um bestimmte Abfragen anzuzielen.

Hier ist ein kurzes Beispiel, wie Sie Serverfunktionen verwenden können, um eine Mutation auf dem Server durchzuführen und die Daten auf dem Client zu invalidieren.

tsx
import { createServerFn } from '@tanstack/solid-start'

const UserSchema = z.object({
  id: z.string(),
  name: z.string(),
})

const updateUser = createServerFn({ method: 'POST' })
  .validator(UserSchema)
  .handler(async ({ data }) => {
    return db
      .update(users)
      .set({ name: data.name })
      .where(eq(users.id, data.id))
  })

// Somewhere else in your application
await updateUser({ data: { id: '1', name: 'John' } })
import { createServerFn } from '@tanstack/solid-start'

const UserSchema = z.object({
  id: z.string(),
  name: z.string(),
})

const updateUser = createServerFn({ method: 'POST' })
  .validator(UserSchema)
  .handler(async ({ data }) => {
    return db
      .update(users)
      .set({ name: data.name })
      .where(eq(users.id, data.id))
  })

// Somewhere else in your application
await updateUser({ data: { id: '1', name: 'John' } })

Weitere Informationen zu Mutationen finden Sie im Mutationsleitfaden.

Daten laden

Eine weitere leistungsstarke Funktion von TanStack Router ist das Datenladen. Dies ermöglicht es Ihnen, Daten für SSR abzurufen und Routendaten vor dem Rendern vorab zu laden. Dies geschieht über die Funktion loader einer Route.

Hier ist ein kurzer Überblick, wie das Datenladen funktioniert.

  • Datenladen geschieht über die Funktion loader einer Route.
  • Datenlader sind isomorph, d. h. sie werden sowohl auf dem Server als auch auf dem Client ausgeführt.
  • Um nur serverseitige Logik auszuführen, rufen Sie eine Serverfunktion innerhalb des Laders auf.
  • Ähnlich wie bei TanStack Query werden Datenlader auf dem Client zwischengespeichert und wiederverwendet und sogar im Hintergrund neu abgerufen, wenn die Daten veraltet sind.

Weitere Informationen zum Datenladen finden Sie im Datenlade-Leitfaden.

Unsere Partner
Code Rabbit
Netlify
Neon
Clerk
Convex
Sentry
Prisma
Bytes abonnieren

Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.

Bytes

Kein Spam. Jederzeit kündbar.

Bytes abonnieren

Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.

Bytes

Kein Spam. Jederzeit kündbar.