react-tanstack-senior

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

React + TanStack Senior Developer Skill

React + TanStack 资深开发者技能

Core Philosophy

核心理念

KISS > Clever Code
Readability > Brevity  
Explicit > Implicit
Composition > Inheritance
Colocation > Separation
Type Safety > Any
KISS > 炫技代码
可读性 > 简洁性  
显式 > 隐式
组合 > 继承
就近放置 > 分离
类型安全 > Any

Quick Decision Tree

快速决策树

State Management:
  • Server state → TanStack Query (WAJIB)
  • URL state → TanStack Router search params
  • Form state → TanStack Form atau React Hook Form
  • Global UI state → Zustand (bukan Redux)
  • Local UI state → useState/useReducer
Routing:
  • SPA → TanStack Router
  • Full-stack SSR → TanStack Start
  • Existing Next.js → tetap Next.js
状态管理:
  • 服务端状态 → TanStack Query(必须)
  • URL状态 → TanStack Router 查询参数
  • 表单状态 → TanStack Form 或 React Hook Form
  • 全局UI状态 → Zustand(而非Redux)
  • 本地UI状态 → useState/useReducer
路由:
  • SPA → TanStack Router
  • 全栈SSR → TanStack Start
  • 现有Next.js项目 → 继续使用Next.js

Project Setup Workflow

项目搭建流程

  1. Determine project type:
    • SPA/Client-only? → Vite + TanStack Router + Query
    • Full-stack SSR? → TanStack Start (Vinxi-based)
    • Existing project? → Incremental adoption
  2. Initialize project → See folder-structure.md
  3. Setup core dependencies → See recommended-libraries.md
  1. 确定项目类型:
    • SPA/纯客户端? → Vite + TanStack Router + Query
    • 全栈SSR? → TanStack Start(基于Vinxi)
    • 现有项目? → 逐步适配
  2. 初始化项目 → 查看 folder-structure.md
  3. 配置核心依赖 → 查看 recommended-libraries.md

TanStack Ecosystem References

TanStack生态系统参考资料

LibraryWhen to Read
tanstack-query.mdData fetching, caching, mutations
tanstack-router.mdType-safe routing, loaders, search params
tanstack-table.mdComplex tables, sorting, filtering, pagination
tanstack-form.mdForm validation, field arrays, async validation
tanstack-start.mdFull-stack SSR framework
适用场景
tanstack-query.md数据获取、缓存、变更
tanstack-router.md类型安全路由、加载器、查询参数
tanstack-table.md复杂表格、排序、筛选、分页
tanstack-form.md表单验证、字段数组、异步验证
tanstack-start.md全栈SSR框架

Code Quality Standards

代码质量标准

Naming Conventions

命名规范

typescript
// Components: PascalCase dengan suffix deskriptif
UserProfileCard.tsx      // ✓
UserCard.tsx             // ✗ terlalu generic
user-profile.tsx         // ✗ wrong case

// Hooks: camelCase dengan prefix 'use'
useUserProfile()         // ✓
useGetUserProfile()      // ✗ redundant 'Get'
getUserProfile()         // ✗ missing 'use'

// Query keys: array dengan hierarchy
['users', 'list', { status }]           // ✓
['usersList']                            // ✗ tidak granular
`users-${status}`                        // ✗ string interpolation

// Files: kebab-case untuk non-components
api-client.ts            // ✓
apiClient.ts             // ✗ 
typescript
// 组件:PascalCase + 描述性后缀
UserProfileCard.tsx      // ✓
UserCard.tsx             // ✗ 过于通用
user-profile.tsx         // ✗ 大小写错误

// Hooks:camelCase + 'use'前缀
useUserProfile()         // ✓
useGetUserProfile()      // ✗ 冗余的'Get'
getUserProfile()         // ✗ 缺少'use'前缀

// Query键:层级化数组
['users', 'list', { status }]           // ✓
['usersList']                            // ✗ 不够细化
`users-${status}`                        // ✗ 字符串插值

// 文件:非组件使用kebab-case
api-client.ts            // ✓
apiClient.ts             // ✗ 

Component Structure Pattern

组件结构模式

typescript
// 1. Imports (grouped: external → internal → types)
import { useSuspenseQuery } from '@tanstack/react-query'
import { userQueries } from '@/features/users/api'
import type { User } from '@/features/users/types'

// 2. Types (colocated, tidak di file terpisah kecuali shared)
interface UserCardProps {
  userId: string
  onSelect?: (user: User) => void
}

// 3. Component (single responsibility)
export function UserCard({ userId, onSelect }: UserCardProps) {
  // 3a. Queries/mutations first
  const { data: user } = useSuspenseQuery(userQueries.detail(userId))
  
  // 3b. Derived state (useMemo hanya jika expensive)
  const fullName = `${user.firstName} ${user.lastName}`
  
  // 3c. Handlers (useCallback hanya jika passed to memoized children)
  const handleClick = () => onSelect?.(user)
  
  // 3d. Early returns untuk edge cases
  if (!user.isActive) return null
  
  // 3e. JSX (clean, minimal nesting)
  return (
    <article onClick={handleClick} className="user-card">
      <h3>{fullName}</h3>
      <p>{user.email}</p>
    </article>
  )
}
typescript
// 1. 导入(分组:外部 → 内部 → 类型)
import { useSuspenseQuery } from '@tanstack/react-query'
import { userQueries } from '@/features/users/api'
import type { User } from '@/features/users/types'

// 2. 类型(就近放置,除非是共享类型否则不单独放文件)
interface UserCardProps {
  userId: string
  onSelect?: (user: User) => void
}

// 3. 组件(单一职责)
export function UserCard({ userId, onSelect }: UserCardProps) {
  // 3a. 优先放置查询/变更逻辑
  const { data: user } = useSuspenseQuery(userQueries.detail(userId))
  
  // 3b. 派生状态(仅在计算昂贵时使用useMemo)
  const fullName = `${user.firstName} ${user.lastName}`
  
  // 3c. 事件处理函数(仅在传递给已记忆的子组件时使用useCallback)
  const handleClick = () => onSelect?.(user)
  
  // 3d. 边缘情况提前返回
  if (!user.isActive) return null
  
  // 3e. JSX(简洁,尽量减少嵌套)
  return (
    <article onClick={handleClick} className="user-card">
      <h3>{fullName}</h3>
      <p>{user.email}</p>
    </article>
  )
}

Anti-Patterns to AVOID

需要避免的反模式

typescript
// ❌ NEVER: useEffect untuk data fetching
useEffect(() => {
  fetch('/api/users').then(setUsers)
}, [])

// ✅ ALWAYS: TanStack Query
const { data: users } = useQuery(userQueries.list())

// ❌ NEVER: Prop drilling lebih dari 2 level
<Parent userData={user}>
  <Child userData={user}>
    <GrandChild userData={user} />

// ✅ ALWAYS: Context atau query di level yang butuh
function GrandChild() {
  const { data: user } = useQuery(userQueries.current())
}

// ❌ NEVER: Premature optimization
const value = useMemo(() => a + b, [a, b]) // simple math

// ✅ ALWAYS: Optimize only when measured
const value = a + b // just calculate

// ❌ NEVER: Index as key untuk dynamic lists
{items.map((item, i) => <Item key={i} />)}

// ✅ ALWAYS: Stable unique identifier
{items.map(item => <Item key={item.id} />)}
typescript
// ❌ 绝对不要:使用useEffect进行数据获取
useEffect(() => {
  fetch('/api/users').then(setUsers)
}, [])

// ✅ 一定要:使用TanStack Query
const { data: users } = useQuery(userQueries.list())

// ❌ 绝对不要:属性透传超过2层
<Parent userData={user}>
  <Child userData={user}>
    <GrandChild userData={user} />

// ✅ 一定要:在需要的层级使用Context或查询
function GrandChild() {
  const { data: user } = useQuery(userQueries.current())
}

// ❌ 绝对不要:过早优化
const value = useMemo(() => a + b, [a, b]) // 简单计算

// ✅ 一定要:仅在有性能问题时再优化
const value = a + b // 直接计算即可

// ❌ 绝对不要:在动态列表中使用索引作为key
{items.map((item, i) => <Item key={i} />)}

// ✅ 一定要:使用稳定的唯一标识符
{items.map(item => <Item key={item.id} />)}

Debugging Guide

调试指南

See debugging-guide.md for:
  • React DevTools profiling
  • TanStack Query DevTools
  • Memory leak detection
  • Performance bottleneck identification
  • Common error patterns
查看 debugging-guide.md 了解:
  • React DevTools 性能分析
  • TanStack Query DevTools
  • 内存泄漏检测
  • 性能瓶颈识别
  • 常见错误模式

Common Pitfalls & Bugs

常见陷阱与Bug

See common-pitfalls.md for:
  • Stale closure bugs
  • Race conditions
  • Memory leaks patterns
  • Hydration mismatches
  • Query invalidation mistakes
查看 common-pitfalls.md 了解:
  • 陈旧闭包Bug
  • 竞态条件
  • 内存泄漏模式
  • Hydration不匹配
  • 查询失效错误

Performance Checklist

性能检查清单

markdown
□ Bundle size < 200KB gzipped (initial)
□ Largest Contentful Paint < 2.5s
□ No unnecessary re-renders (React DevTools)
□ Images lazy loaded
□ Code splitting per route
□ Query deduplication working
□ No memory leaks (heap snapshot stable)
markdown
□ 初始包体积 gzipped 小于200KB
□ 最大内容绘制时间小于2.5秒
□ 无不必要的重渲染(通过React DevTools检查)
□ 图片已懒加载
□ 按路由进行代码分割
□ 查询去重生效
□ 无内存泄漏(堆快照稳定)

Code Review Checklist

代码评审检查清单

markdown
□ No `any` types (use `unknown` if needed)
□ No `// @ts-ignore` tanpa penjelasan
□ Error boundaries di route level
□ Loading states handled
□ Empty states handled
□ Error states handled  
□ Accessibility (aria labels, keyboard nav)
□ No hardcoded strings (i18n ready)
□ No console.log in production code
□ Tests untuk business logic
markdown
□ 无`any`类型(必要时使用`unknown`□ 无未加说明的`// @ts-ignore`
□ 路由层级已添加错误边界
□ 已处理加载状态
□ 已处理空状态
□ 已处理错误状态  
□ 可访问性(aria标签、键盘导航)
□ 无硬编码字符串(支持国际化)
□ 生产代码中无console.log
□ 业务逻辑已编写测试