SuperAPI AI 工具集

react-start

前端与建站

查看项目

更新于 10-16 14:59

技能介绍

用途

React Start(@tanstack/react-start)提供 TanStack Start 在 React 下的绑定、项目配置与使用模式。该技能建立在 start-core 之上,建议先阅读 start-core 了解基础概念;React Server Components 相关模式参见 react-start/server-components。

它明确区别于 Next.js 或 Remix:这是完全不同的框架,API 也不相同。

主要能力

@tanstack/react-start 重新导出 @tanstack/start-client-core 的全部内容,并额外提供:

  • useServerFn —— 在 React 组件中调用服务端函数的 Hook。

核心 API(createServerFn、createMiddleware、createStart、createIsomorphicFn、createServerOnlyFn、createClientOnlyFn)均可从 @tanstack/react-start 导入。

服务端工具(getRequest、getRequestHeader、setResponseHeader、setResponseHeaders、setResponseStatus)从 @tanstack/react-start/server 导入。

重要约束:所有代码默认是同构的,loader 在服务端和客户端都会运行;服务端专属逻辑需使用 createServerFn。类型完全推断,不要做类型转换或对已推断值添加类型注解。

使用方式

完整项目搭建步骤:

  1. 安装依赖:
npm i @tanstack/react-start @tanstack/react-router react react-dom
npm i -D vite @vitejs/plugin-react typescript @types/react @types/react-dom
  1. package.json:
{
  "type": "module",
  "scripts": {
    "dev": "vite dev",
    "build": "vite build",
    "start": "node .output/server/index.mjs"
  }
}
  1. tsconfig.json:
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "moduleResolution": "Bundler",
    "module": "ESNext",
    "target": "ES2022",
    "skipLibCheck": true,
    "strictNullChecks": true
  }
}
  1. vite.config.ts:
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import viteReact from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [
    tanstackStart(), // 必须放在 react() 之前
    viteReact(),
  ],
})
  1. 路由工厂(src/router.tsx):
import { createRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'

export function getRouter() {
  const router = createRouter({
    routeTree,
    scrollRestoration: true,
  })
  return router
}
  1. 根路由(src/routes/__root.tsx):
import type { ReactNode } from 'react'
import {
  Outlet,
  createRootRoute,
  HeadContent,
  Scripts,
} from '@tanstack/react-router'

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

function RootComponent() {
  return (
    <RootDocument>
      <Outlet />
    </RootDocument>
  )
}

function RootDocument({ children }: Readonly<{ children: ReactNode }>) {
  return (
    <html>
      <head>
        <HeadContent />
      </head>
      <body>
        {children}
        <Scripts />
      </body>
    </html>
  )
}
  1. 索引路由(src/routes/index.tsx):
import { createFileRoute } from '@tanstack/react-router'
import { createServerFn } from '@tanstack/react-start'

const getGreeting = createServerFn({ method: 'GET' }).handler(async () => {
  return 'Hello from TanStack Start!'
})

export const Route = createFileRoute('/')({
  loader: () => getGreeting(),
  component: HomePage,
})

function HomePage() {
  const greeting = Route.useLoaderData()
  return <h1>{greeting}</h1>
}

使用 useServerFn 在组件中调用服务端函数:

import { createServerFn, useServerFn } from '@tanstack/react-start'

const updatePost = createServerFn({ method: 'POST' })
  .inputValidator((data: { id: string; title: string }) => data)
  .handler(async ({ data }) => {
    await db.posts.update(data.id, { title: data.title })
    return { success: true }
  })

function EditPostForm({ postId }: { postId: string }) {
  const updatePostFn = useServerFn(updatePost)
  const [title, setTitle] = useState('')

  return (
    <form
      onSubmit={async (e) => {
        e.preventDefault()
        await updatePostFn({ data: { id: postId, title } })
      }}
    >
      <input value={title} onChange={(e) => setTitle(e.target.value)} />
      <button type="submit">Save</button>
    </form>
  )
}

全局 Start 配置(src/start.ts):

import { createStart, createMiddleware } from '@tanstack/react-start'

const requestLogger = createMiddleware().server(async ({ next, request }) => {
  console.log(`${request.method} ${request.url}`)
  return next()
})

export const startInstance = createStart(() => ({
  requestMiddleware: [requestLogger],
}))

React 专属组件

@tanstack/react-router 的路由组件都可在 Start 中使用:

  • RouterProvider —— Start 中不需要(自动处理)
  • Outlet —— 渲染匹配的子路由
  • Link —— 类型安全导航
  • Navigate —— 声明式重定向
  • HeadContent —— 渲染 head 标签(必须位于 head 内)
  • Scripts —— 渲染 body 脚本(必须位于 body 内)
  • Await —— 配合 Suspense 渲染延迟数据
  • ClientOnly —— 仅在 hydration 后渲染子节点
  • CatchBoundary —— 错误边界

Hooks 参考:useRouter()、useRouterState()、useNavigate()、useSearch({ from })、useParams({ from })、useLoaderData({ from })、useMatch({ from })、useRouteContext({ from }),以及路由文件内推荐的 Route.useLoaderData() 和 Route.useSearch()。

常见错误

  1. 关键:从错误的包导入。createServerFn 应来自 @tanstack/react-start,而不是 @tanstack/react-router;路由 API(createFileRoute、Link)来自 @tanstack/react-router(Start 也重新导出)。

  2. 高:在 beforeLoad 或 loader 中使用 React Hook。它们不是 React 组件,状态应通过路由上下文传递。

  3. 高:遗漏 Scripts 组件。根路由 body 中缺少 <Scripts /> 会导致客户端 JavaScript 不加载、应用无法 hydration。

适用场景

需要使用 React 构建 TanStack Start 应用、配置项目结构、定义服务端函数与在组件中调用、配置全局 Start 中间件的场景。

限制

资料未提供该技能的安装方式、收费、价格或平台限制等信息。