react-ui

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

React UI

React UI

For any val that renders a UI, prefer to build it with React components in
.tsx
files, unless the user states otherwise. The
templates/react-hono-starter
template is set up for this — start there with
remix_val
instead of building from scratch.
对于任何渲染 UI 的 val,除非用户另有说明,否则应优先使用
.tsx
文件中的 React 组件进行构建。
templates/react-hono-starter
模板已为此配置好——请使用
remix_val
从该模板开始,而不是从头构建。

File conventions

文件约定

Put markup, styles, and scripts in real files — avoid template literal strings (e.g.
new Response(\
<html>...</html>`)`). Code in template strings has no syntax highlighting, no linting, no type checking, and is unreviewable.
  • .tsx
    — React/JSX components, any UI with logic or interactivity
  • .html
    — purely static markup
  • .ts
    — server code and scripts
Build UI component by component in
.tsx
files. Compose small components rather than rendering one giant page.
将标记、样式和脚本放入实际文件中——避免使用模板字符串(例如
new Response(\<html>...<\/html>\
)`)。模板字符串中的代码没有语法高亮,无法进行 lint 或类型检查,而且难以审查。
  • .tsx
    — React/JSX 组件,带逻辑或交互性的任何 UI
  • .html
    — 纯静态标记
  • .ts
    — 服务端代码和脚本
应在
.tsx
文件中逐个组件构建 UI。组合小型组件,而不是渲染一个巨大的页面。

Styling: Twind + Tailwind

样式:Twind + Tailwind

Prefer Twind to apply Tailwind utility classes at runtime — no build step required. Add the script to your HTML shell:
html
<script src="https://cdn.twind.style" crossorigin></script>
Then use Tailwind classes directly in JSX:
tsx
<div className="flex items-center gap-4 p-6 rounded-lg bg-white shadow">
  <h1 className="text-2xl font-bold">Hello</h1>
</div>
Avoid inline
<style>
tags, CSS-in-JS objects, or separate
.css
files, unless the user says otherwise.
优先使用 Twind 在运行时应用 Tailwind 工具类,无需构建步骤。将以下脚本添加到 HTML shell:
html
<script src="https://cdn.twind.style" crossorigin></script>
然后在 JSX 中直接使用 Tailwind 类:
tsx
<div className="flex items-center gap-4 p-6 rounded-lg bg-white shadow">
  <h1 className="text-2xl font-bold">Hello</h1>
</div>
避免使用内联
<style>
标签、CSS-in-JS 对象或单独的
.css
文件,除非用户另有说明。

Serving assets: versioned + immutable

提供资源:版本化 + 不可变

Serve client modules with
serveImmutableFile
from
std/utils
— browsers cache them immutably, and publishing bumps the val's version, which invalidates automatically (full pattern: the
client-side-js
skill). A never-cached
frontend/root.tsx
shell (hono/jsx) stamps the entry and favicon with
immutableFileUrl
:
tsx
// frontend/root.tsx — in the Root() HTML shell:
<script src={immutableFileUrl("/frontend/index.tsx")} type="module" />

// index.ts:
app.get("/", (c) => c.html(Root()));
app.get("/__immutable/*", (c) => serveImmutableFile(c.req.path));
使用
std/utils
中的
serveImmutableFile
提供客户端模块——浏览器会对其进行不可变缓存,而发布时会提升 val 的版本,从而自动使缓存失效(完整模式:
client-side-js
skill)。一个从不被缓存的
frontend/root.tsx
shell(hono/jsx)会使用
immutableFileUrl
为入口和 favicon 添加版本戳:
tsx
// frontend/root.tsx — in the Root() HTML shell:
<script src={immutableFileUrl("/frontend/index.tsx")} type="module" />

// index.ts:
app.get("/", (c) => c.html(Root()));
app.get("/__immutable/*", (c) => serveImmutableFile(c.req.path));

View source link

查看源代码链接

Every UI val should expose a way for users to see and remix its source. Both parts are required:
  1. Backend route:
    ts
    import { parseVal } from "https://esm.town/v/std/utils/index.ts";
    app.get("/source", (c) => c.redirect(parseVal().links.self.val));
  2. Visible link in the frontend:
    tsx
    <a href="/source">view source</a>
每个 UI val 都应提供一种让用户查看并改编其源代码的方式。以下两部分均为必需:
  1. 后端路由:
    ts
    import { parseVal } from "https://esm.town/v/std/utils/index.ts";
    app.get("/source", (c) => c.redirect(parseVal().links.self.val));
  2. 前端可见链接:
    tsx
    <a href="/source">view source</a>

React version pinning

React 版本锁定

A common error —
"Cannot read properties of null (reading 'useState')"
— means a React sub-dependency is loading a different React version. Pin all React-related imports to 18.2.0:
ts
import SomeLib from "https://esm.sh/some-lib?deps=react@18.2.0,react-dom@18.2.0";
一种常见错误——
"Cannot read properties of null (reading 'useState')"
——表示某个 React 子依赖项加载了另一个 React 版本。将所有与 React 相关的导入固定为 18.2.0:
ts
import SomeLib from "https://esm.sh/some-lib?deps=react@18.2.0,react-dom@18.2.0";

Assets

资源

Do not use external images or hosted assets that may break. Prefer:
  • Emojis or unicode symbols
  • Inline SVG
  • Icon fonts via CDN (Lucide, Font Awesome)
不要使用可能失效的外部图片或托管资源。优先使用:
  • Emoji 或 Unicode 符号
  • 内联 SVG
  • 通过 CDN 提供的图标字体(Lucide、Font Awesome)

Surfacing client-side errors

呈现客户端错误

To send browser errors back to val logs (visible via
get_logs
), include this script in your HTML shell:
html
<script src="https://esm.town/v/std/catch"></script>
要在 HTML shell 中加入以下脚本,将浏览器错误发送回 val 日志(可通过
get_logs
查看):
html
<script src="https://esm.town/v/std/catch"></script>

Verifying changes

验证更改

After editing a UI val, call
fetch_val_endpoint
to confirm the page renders without error, then check
get_logs
for any client-side errors. Don't report the change as done without both.
编辑 UI val 后,调用
fetch_val_endpoint
确认页面渲染无误,然后检查
get_logs
是否有客户端错误。在这两项检查都完成之前,不要报告更改已完成。