react-dev by davila7/claude-code-templates
npx skills add https://github.com/davila7/claude-code-templates --skill react-dev类型安全的 React = 编译时保证 = 自信地重构。
<when_to_use>
不适用于:非 React 的 TypeScript、原生 JS React
</when_to_use>
<react_19_changes>
React 19 的重大变更需要进行迁移。关键模式:
ref 作为 prop - forwardRef 已弃用:
// React 19 - ref 作为常规 prop
type ButtonProps = {
ref?: React.Ref<HTMLButtonElement>;
} & React.ComponentPropsWithoutRef<'button'>;
function Button({ ref, children, ...props }: ButtonProps) {
return <button ref={ref} {...props}>{children}</button>;
}
useActionState - 替代 useFormState:
import { useActionState } from 'react';
type FormState = { errors?: string[]; success?: boolean };
function Form() {
const [state, formAction, isPending] = useActionState(submitAction, {});
return <form action={formAction}>...</form>;
}
use() - 解包 Promise/上下文:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
function UserProfile({ userPromise }: { userPromise: Promise<User> }) {
const user = use(userPromise); // 挂起直到解析完成
return <div>{user.name}</div>;
}
有关 useOptimistic、useTransition 和迁移清单,请参阅 react-19-patterns.md。
</react_19_changes>
<component_patterns>
Props - 扩展原生元素:
type ButtonProps = {
variant: 'primary' | 'secondary';
} & React.ComponentPropsWithoutRef<'button'>;
function Button({ variant, children, ...props }: ButtonProps) {
return <button className={variant} {...props}>{children}</button>;
}
Children 类型:
type Props = {
children: React.ReactNode; // 任何可渲染的内容
icon: React.ReactElement; // 单个元素
render: (data: T) => React.ReactNode; // Render prop
};
用于变体 props 的可辨识联合:
type ButtonProps =
| { variant: 'link'; href: string }
| { variant: 'button'; onClick: () => void };
function Button(props: ButtonProps) {
if (props.variant === 'link') {
return <a href={props.href}>Link</a>;
}
return <button onClick={props.onClick}>Button</button>;
}
</component_patterns>
<event_handlers>
使用特定的事件类型以获得精确的目标类型:
// 鼠标
function handleClick(e: React.MouseEvent<HTMLButtonElement>) {
e.currentTarget.disabled = true;
}
// 表单
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
const formData = new FormData(e.currentTarget);
}
// 输入
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
console.log(e.target.value);
}
// 键盘
function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
if (e.key === 'Enter') e.currentTarget.blur();
}
有关焦点、拖拽、剪贴板、触摸、滚轮事件,请参阅 event-handlers.md。
</event_handlers>
<hooks_typing>
useState - 为联合类型/null 显式指定:
const [user, setUser] = useState<User | null>(null);
const [status, setStatus] = useState<'idle' | 'loading'>('idle');
useRef - DOM 使用 null,可变值直接使用:
const inputRef = useRef<HTMLInputElement>(null); // DOM - 使用 ?.
const countRef = useRef<number>(0); // 可变 - 直接访问
useReducer - 用于 action 的可辨识联合:
type Action =
| { type: 'increment' }
| { type: 'set'; payload: number };
function reducer(state: State, action: Action): State {
switch (action.type) {
case 'set': return { ...state, count: action.payload };
default: return state;
}
}
自定义钩子 - 使用 as const 的元组返回:
function useToggle(initial = false) {
const [value, setValue] = useState(initial);
const toggle = () => setValue(v => !v);
return [value, toggle] as const;
}
useContext - null 守卫模式:
const UserContext = createContext<User | null>(null);
function useUser() {
const user = useContext(UserContext);
if (!user) throw new Error('useUser outside UserProvider');
return user;
}
有关 useCallback、useMemo、useImperativeHandle、useSyncExternalStore,请参阅 hooks.md。
</hooks_typing>
<generic_components>
泛型组件从 props 推断类型 - 调用时无需手动注解。
模式 - 使用 keyof T 表示列键,使用 render props 进行自定义渲染:
type Column<T> = {
key: keyof T;
header: string;
render?: (value: T[keyof T], item: T) => React.ReactNode;
};
type TableProps<T> = {
data: T[];
columns: Column<T>[];
keyExtractor: (item: T) => string | number;
};
function Table<T>({ data, columns, keyExtractor }: TableProps<T>) {
return (
<table>
<thead>
<tr>{columns.map(col => <th key={String(col.key)}>{col.header}</th>)}</tr>
</thead>
<tbody>
{data.map(item => (
<tr key={keyExtractor(item)}>
{columns.map(col => (
<td key={String(col.key)}>
{col.render ? col.render(item[col.key], item) : String(item[col.key])}
</td>
))}
</tr>
))}
</tbody>
</table>
);
}
用于必需属性的约束泛型:
type HasId = { id: string | number };
function List<T extends HasId>({ items }: { items: T[] }) {
return <ul>{items.map(item => <li key={item.id}>...</li>)}</ul>;
}
有关 Select、List、Modal、FormField 模式,请参阅 generic-components.md。
</generic_components>
<server_components>
React 19 服务器组件在服务器端运行,可以是异步的。
异步数据获取:
export default async function UserPage({ params }: { params: { id: string } }) {
const user = await fetchUser(params.id);
return <div>{user.name}</div>;
}
服务器 Actions - 使用 'use server' 进行数据变更:
'use server';
export async function updateUser(userId: string, formData: FormData) {
await db.user.update({ where: { id: userId }, data: { ... } });
revalidatePath(`/users/${userId}`);
}
客户端 + 服务器 Action:
'use client';
import { useActionState } from 'react';
import { updateUser } from '@/actions/user';
function UserForm({ userId }: { userId: string }) {
const [state, formAction, isPending] = useActionState(
(prev, formData) => updateUser(userId, formData), {}
);
return <form action={formAction}>...</form>;
}
使用 use() 传递 Promise:
// 服务器端:传递 Promise 而不使用 await
async function Page() {
const userPromise = fetchUser('123');
return <UserProfile userPromise={userPromise} />;
}
// 客户端:使用 use() 解包
'use client';
function UserProfile({ userPromise }: { userPromise: Promise<User> }) {
const user = use(userPromise);
return <div>{user.name}</div>;
}
有关并行获取、流式传输、错误边界,请参阅 server-components.md。
</server_components>
TanStack Router 和 React Router v7 都提供了类型安全的路由解决方案。
TanStack Router - 使用 Zod 验证实现编译时类型安全:
import { createRoute } from '@tanstack/react-router';
import { z } from 'zod';
const userRoute = createRoute({
path: '/users/$userId',
component: UserPage,
loader: async ({ params }) => ({ user: await fetchUser(params.userId) }),
validateSearch: z.object({
tab: z.enum(['profile', 'settings']).optional(),
page: z.number().int().positive().default(1),
}),
});
function UserPage() {
const { user } = useLoaderData({ from: userRoute.id });
const { tab, page } = useSearch({ from: userRoute.id });
const { userId } = useParams({ from: userRoute.id });
}
React Router v7 - 通过 Framework Mode 自动生成类型:
import type { Route } from "./+types/user";
export async function loader({ params }: Route.LoaderArgs) {
return { user: await fetchUser(params.userId) };
}
export default function UserPage({ loaderData }: Route.ComponentProps) {
const { user } = loaderData; // 从 loader 获得类型
return <h1>{user.name}</h1>;
}
有关 TanStack 模式,请参阅 tanstack-router.md;有关 React Router 模式,请参阅 react-router.md。
始终:
绝不:
对事件处理器使用 any
对 children 使用 JSX.Element(使用 ReactNode)
在 React 19+ 中使用 forwardRef
使用 useFormState(已弃用)
忘记处理 DOM refs 的 null 情况
在同一文件中混合服务器/客户端组件
在传递给 use() 时 await Promise
hooks.md - useState、useRef、useReducer、useContext、自定义钩子
event-handlers.md - 所有事件类型、通用处理器
react-19-patterns.md - useActionState、use()、useOptimistic、迁移
generic-components.md - Table、Select、List、Modal 模式
server-components.md - 异步组件、Server Actions、流式传输
tanstack-router.md - TanStack Router 类型化路由、搜索参数、导航
react-router.md - React Router v7 loaders、actions、类型生成、表单
每周安装量
258
仓库
GitHub Stars
22.6K
首次出现
2026年1月25日
安全审计
安装于
opencode211
gemini-cli205
codex200
github-copilot191
claude-code181
cursor167
Type-safe React = compile-time guarantees = confident refactoring.
<when_to_use>
NOT for: non-React TypeScript, vanilla JS React
</when_to_use>
<react_19_changes>
React 19 breaking changes require migration. Key patterns:
ref as prop - forwardRef deprecated:
// React 19 - ref as regular prop
type ButtonProps = {
ref?: React.Ref<HTMLButtonElement>;
} & React.ComponentPropsWithoutRef<'button'>;
function Button({ ref, children, ...props }: ButtonProps) {
return <button ref={ref} {...props}>{children}</button>;
}
useActionState - replaces useFormState:
import { useActionState } from 'react';
type FormState = { errors?: string[]; success?: boolean };
function Form() {
const [state, formAction, isPending] = useActionState(submitAction, {});
return <form action={formAction}>...</form>;
}
use() - unwraps promises/context:
function UserProfile({ userPromise }: { userPromise: Promise<User> }) {
const user = use(userPromise); // Suspends until resolved
return <div>{user.name}</div>;
}
See react-19-patterns.md for useOptimistic, useTransition, migration checklist.
</react_19_changes>
<component_patterns>
Props - extend native elements:
type ButtonProps = {
variant: 'primary' | 'secondary';
} & React.ComponentPropsWithoutRef<'button'>;
function Button({ variant, children, ...props }: ButtonProps) {
return <button className={variant} {...props}>{children}</button>;
}
Children typing :
type Props = {
children: React.ReactNode; // Anything renderable
icon: React.ReactElement; // Single element
render: (data: T) => React.ReactNode; // Render prop
};
Discriminated unions for variant props:
type ButtonProps =
| { variant: 'link'; href: string }
| { variant: 'button'; onClick: () => void };
function Button(props: ButtonProps) {
if (props.variant === 'link') {
return <a href={props.href}>Link</a>;
}
return <button onClick={props.onClick}>Button</button>;
}
</component_patterns>
<event_handlers>
Use specific event types for accurate target typing:
// Mouse
function handleClick(e: React.MouseEvent<HTMLButtonElement>) {
e.currentTarget.disabled = true;
}
// Form
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
const formData = new FormData(e.currentTarget);
}
// Input
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
console.log(e.target.value);
}
// Keyboard
function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
if (e.key === 'Enter') e.currentTarget.blur();
}
See event-handlers.md for focus, drag, clipboard, touch, wheel events.
</event_handlers>
<hooks_typing>
useState - explicit for unions/null:
const [user, setUser] = useState<User | null>(null);
const [status, setStatus] = useState<'idle' | 'loading'>('idle');
useRef - null for DOM, value for mutable:
const inputRef = useRef<HTMLInputElement>(null); // DOM - use ?.
const countRef = useRef<number>(0); // Mutable - direct access
useReducer - discriminated unions for actions:
type Action =
| { type: 'increment' }
| { type: 'set'; payload: number };
function reducer(state: State, action: Action): State {
switch (action.type) {
case 'set': return { ...state, count: action.payload };
default: return state;
}
}
Custom hooks - tuple returns with as const:
function useToggle(initial = false) {
const [value, setValue] = useState(initial);
const toggle = () => setValue(v => !v);
return [value, toggle] as const;
}
useContext - null guard pattern:
const UserContext = createContext<User | null>(null);
function useUser() {
const user = useContext(UserContext);
if (!user) throw new Error('useUser outside UserProvider');
return user;
}
See hooks.md for useCallback, useMemo, useImperativeHandle, useSyncExternalStore.
</hooks_typing>
<generic_components>
Generic components infer types from props - no manual annotations at call site.
Pattern - keyof T for column keys, render props for custom rendering:
type Column<T> = {
key: keyof T;
header: string;
render?: (value: T[keyof T], item: T) => React.ReactNode;
};
type TableProps<T> = {
data: T[];
columns: Column<T>[];
keyExtractor: (item: T) => string | number;
};
function Table<T>({ data, columns, keyExtractor }: TableProps<T>) {
return (
<table>
<thead>
<tr>{columns.map(col => <th key={String(col.key)}>{col.header}</th>)}</tr>
</thead>
<tbody>
{data.map(item => (
<tr key={keyExtractor(item)}>
{columns.map(col => (
<td key={String(col.key)}>
{col.render ? col.render(item[col.key], item) : String(item[col.key])}
</td>
))}
</tr>
))}
</tbody>
</table>
);
}
Constrained generics for required properties:
type HasId = { id: string | number };
function List<T extends HasId>({ items }: { items: T[] }) {
return <ul>{items.map(item => <li key={item.id}>...</li>)}</ul>;
}
See generic-components.md for Select, List, Modal, FormField patterns.
</generic_components>
<server_components>
React 19 Server Components run on server, can be async.
Async data fetching :
export default async function UserPage({ params }: { params: { id: string } }) {
const user = await fetchUser(params.id);
return <div>{user.name}</div>;
}
Server Actions - 'use server' for mutations:
'use server';
export async function updateUser(userId: string, formData: FormData) {
await db.user.update({ where: { id: userId }, data: { ... } });
revalidatePath(`/users/${userId}`);
}
Client + Server Action :
'use client';
import { useActionState } from 'react';
import { updateUser } from '@/actions/user';
function UserForm({ userId }: { userId: string }) {
const [state, formAction, isPending] = useActionState(
(prev, formData) => updateUser(userId, formData), {}
);
return <form action={formAction}>...</form>;
}
use() for promise handoff :
// Server: pass promise without await
async function Page() {
const userPromise = fetchUser('123');
return <UserProfile userPromise={userPromise} />;
}
// Client: unwrap with use()
'use client';
function UserProfile({ userPromise }: { userPromise: Promise<User> }) {
const user = use(userPromise);
return <div>{user.name}</div>;
}
See server-components.md for parallel fetching, streaming, error boundaries.
</server_components>
Both TanStack Router and React Router v7 provide type-safe routing solutions.
TanStack Router - Compile-time type safety with Zod validation:
import { createRoute } from '@tanstack/react-router';
import { z } from 'zod';
const userRoute = createRoute({
path: '/users/$userId',
component: UserPage,
loader: async ({ params }) => ({ user: await fetchUser(params.userId) }),
validateSearch: z.object({
tab: z.enum(['profile', 'settings']).optional(),
page: z.number().int().positive().default(1),
}),
});
function UserPage() {
const { user } = useLoaderData({ from: userRoute.id });
const { tab, page } = useSearch({ from: userRoute.id });
const { userId } = useParams({ from: userRoute.id });
}
React Router v7 - Automatic type generation with Framework Mode:
import type { Route } from "./+types/user";
export async function loader({ params }: Route.LoaderArgs) {
return { user: await fetchUser(params.userId) };
}
export default function UserPage({ loaderData }: Route.ComponentProps) {
const { user } = loaderData; // Typed from loader
return <h1>{user.name}</h1>;
}
See tanstack-router.md for TanStack patterns and react-router.md for React Router patterns.
ALWAYS:
NEVER:
any for event handlers
JSX.Element for children (use ReactNode)
forwardRef in React 19+
useFormState (deprecated)
Forget null handling for DOM refs
Mix Server/Client components in same file
Await promises when passing to use()
hooks.md - useState, useRef, useReducer, useContext, custom hooks
event-handlers.md - all event types, generic handlers
react-19-patterns.md - useActionState, use(), useOptimistic, migration
generic-components.md - Table, Select, List, Modal patterns
server-components.md - async components, Server Actions, streaming
tanstack-router.md - TanStack Router typed routes, search params, navigation
Weekly Installs
258
Repository
GitHub Stars
22.6K
First Seen
Jan 25, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode211
gemini-cli205
codex200
github-copilot191
claude-code181
cursor167
Flutter应用架构设计指南:分层结构、数据层实现与最佳实践
3,400 周安装
react-router.md - React Router v7 loaders, actions, type generation, forms