create-hokage-js-app
Version:
🔥 Best CLI tool to create a MERN stack template. Quick, clean, and customizable.
121 lines (87 loc) • 4.64 kB
Markdown
# React Standards
Measurable rules for React (and React + TypeScript). Apply **in addition to** `coding.md`, `typescript.md` (if TS), and `frontend.md`. Every rule is **PASS** or **FAIL**.
## Components
| # | Rule | Pass/Fail |
|---|------|-----------|
| R1 | Function components only in new code | FAIL: new class components (unless error boundary required and project lacks alternative) |
| R2 | One primary component per file | FAIL: multiple unrelated exported components in one file without project precedent |
| R3 | Component file ≤ 150 lines | FAIL: > 150 without extract or `EXCEPTION: component-size` |
| R4 | Name matches file | FAIL: `UserCard` in `helpers.tsx` |
| R5 | Props typed (TS) or PropTypes only if project requires | FAIL: untyped props in TS codebases |
## Hooks
| # | Rule | Pass/Fail |
|---|------|-----------|
| R6 | Hooks only at top level | FAIL: hooks in conditions/loops |
| R7 | Hook dependency arrays correct | FAIL: missing deps suppressed with eslint-disable without justification |
| R8 | Custom hooks named `useX` and encapsulate one concern | FAIL: `useData` that fetches, caches, and sends analytics |
| R9 | No `useEffect` for pure derived state | FAIL: effect that only sets state from props/state computable during render |
| R10 | Sync external systems in effects; cleanup subscriptions | FAIL: subscribe without unsubscribe |
```text
FAIL:
useEffect(() => setFullName(first + last), [first, last]);
PASS:
const fullName = `${first} ${last}`;
```
## State
| # | Rule | Pass/Fail |
|---|------|-----------|
| R11 | Local UI state stays local | FAIL: global store for ephemeral `isOpen` |
| R12 | Server state via project data library (Query/SWR/etc.) | FAIL: duplicate server cache in Redux/Zustand without reason |
| R13 | Do not store derived state | FAIL: state that is only a function of other state/props |
| R14 | Keys on lists: stable ids | FAIL: `key={index}` on reorderable/insertable lists |
## Rendering & Performance
| # | Rule | Pass/Fail |
|---|------|-----------|
| R15 | No state updates inside render | FAIL |
| R16 | Lists > 100 items: paginate or virtualize | FAIL: render 1000 DOM nodes without virtualization/pagination |
| R17 | `memo` / `useMemo` / `useCallback` only when measured or child cost is real | FAIL: wrapping every component/callback “just in case” |
| R18 | Heavy routes code-split | FAIL: bundling admin-only screens into main path when project already code-splits |
## Effects & Data Fetching
| # | Rule | Pass/Fail |
|---|------|-----------|
| R19 | Fetch in route loaders or dedicated hooks — not deep presentational leaves | FAIL: fetch inside pure UI leaf |
| R20 | Handle loading / empty / error | FAIL: missing any of the three for user-facing fetches |
| R21 | Abort or ignore stale responses | FAIL: setState after unmount / race without guard |
| R22 | No fetch waterfalls when parallel is possible | FAIL: sequential awaits that could be `Promise.all` without dependency |
## Forms & Events
| # | Rule | Pass/Fail |
|---|------|-----------|
| R23 | Prevent double submit | FAIL: button stays active while in-flight with duplicate POSTs possible |
| R24 | Labels associated with inputs | FAIL: placeholder-only inputs |
| R25 | Handler names: `onX` props / `handleX` locals per project | FAIL: vague `click()` |
## Security (React)
| # | Rule | Pass/Fail |
|---|------|-----------|
| R26 | No `dangerouslySetInnerHTML` with unsanitized user content | FAIL |
| R27 | Sanitize with allowlist library if HTML required | FAIL: manual regex sanitize |
| R28 | No secrets in client bundle | FAIL: API secrets in `REACT_APP_*` / `VITE_*` |
## Accessibility
| # | Rule | Pass/Fail |
|---|------|-----------|
| R29 | Interactive elements are `button`/`a` (not clickable `div`) | FAIL: `div onClick` without role/keyboard |
| R30 | Icon-only buttons have aria-label | FAIL: unlabeled |
| R31 | Modals trap focus and restore on close | FAIL: focus lost |
## Testing (React)
| # | Rule | Pass/Fail |
|---|------|-----------|
| R32 | Prefer Testing Library queries (`getByRole`, `getByLabelText`) | FAIL: brittle CSS-class selectors as primary |
| R33 | Assert behavior, not implementation details | FAIL: asserting internal state hooks directly |
| R34 | No committed `.only` / `.skip` | FAIL |
## Self-Review Gate
- [ ] Component ≤ 150 lines or exception documented
- [ ] Hooks rules satisfied; no derived-state effects
- [ ] Loading/empty/error handled
- [ ] No unsafe HTML
- [ ] Lists keyed correctly; large lists bounded
- [ ] A11y basics pass
- [ ] Tests assert user behavior