react
Standards Detection
Search for ESLint config (.eslintrc.*, eslint.config.*, package.json). If found, merge with baseline (ESLint takes precedence). Otherwise use baseline only.
Baseline Standards
Types & Imports
- Use
type(notinterface) - Use
import typefor type-only imports - Naming:
ComponentNameProps,UseHookNameOptions - Order: types → libraries → components → utilities → styles
Naming
| Element | Convention | Example |
|---|---|---|
| Components | PascalCase | UserProfile |
| Variables/functions | camelCase | getUserData |
| Constants | UPPER_SNAKE_CASE | MAX_RETRY_COUNT |
| Event handlers | on* | onClick |
| Hooks | use* | useAuth |
Components
- Functional components with arrow functions
- Destructure props with defaults
- Named exports preferred
- Set
displayName - Memoize:
useCallbackfor callbacks,useMemofor computations - Early returns for guards
- Conditional rendering with
&&
Custom Components
type ComponentNameProps = {}
export const ComponentName: FC<ComponentNameProps> = props => {
const {} = props
}
ComponentName.displayName = 'ComponentName'
Custom Hooks
export function useHookName(options: UseHookNameOptions) {
const { a, b } = options
// a, b
return {}
}
Code Style
- TypeScript strict mode
- Avoid
any→ useunknownor specific types - Prefer
constoverlet - Single responsibility functions
Directory Structure
src/
├── hooks/ # shared hooks
│ ├── index.ts # re-exports all hooks (single import entry)
│ └── useXxx.ts # one hook per file, named useXxx
├── components/ # shared components
│ ├── index.ts # re-exports all components
│ ├── Button/
│ │ ├── index.tsx # exports Button component
│ │ └── index.module.less
│ └── XxxCard/
│ ├── index.tsx # exports XxxCard component
│ └── index.module.less
└── pages/ # organized by page module
└── <Name>/ # <Name> = main component name (e.g., UserProfile)
├── index.tsx # exports the page's main component
├── index.module.less
├── components/ # page-private components (optional)
│ ├── index.ts # re-exports this page's components
│ └── ...
└── hooks/ # page-private hooks (optional)
├── index.ts # re-exports this page's hooks
└── ...
Conventions:
index.tsfor unified exports — keeps imports clean:import { Button } from '@/components'- Named exports only — avoid default exports from shared components
- Directory name = Component name —
pages/UserProfile/index.tsxexportsUserProfile - Co-locate page-specific code — complex pages may have their own
components/andhooks/
Import examples:
// Good
import { Button, useAuth } from '@/components'
import { UserProfile } from '@/pages/UserProfile'
// Avoid
import Button from '@/components/Button' // inconsistent with index.ts pattern
More from vainjs/skills
commit
Generate git commits following Conventional Commits (commitlint) format. Make sure to use this skill whenever the user mentions git commit, commit changes, make a commit, conventional commits, commitlint, or asks to commit any changes — even if they do not explicitly say "skill" or "Conventional Commits". This skill is especially useful when the user says things like "commit this", "commit my changes", "git add and commit", or wants a properly formatted commit message.
10vainjs
Scaffold projects with vainjs conventions for npm packages and Chrome extensions. Make sure to use this skill whenever the user mentions initializing an npm package, creating a new project with Vite or Rollup, setting up a Chrome extension (Manifest V3), scaffolding a library, or running `npm init`, `pnpm create`, or similar scaffold commands — even if they don't explicitly ask for vainjs conventions.
8feishu-news-card
发送飞书卡片消息,用于新闻推送、通知提醒、数据报告等场景。Make sure to use this skill whenever the user mentions 推送新闻、发飞书消息、发送通知卡片、发飞书通知、拉取飞书消息、飞书卡片、Feishu card、Lark card,或任何与飞书/飞书消息推送相关的场景 — even if they don't explicitly say "skill"。
3