--- name: react description: Guides React component implementation, performance optimization, and state management thresholds. Triggered when handling components, pages, or UI logic. --- # React Development Guide This skill provides a comprehensive guide for building React components in the project, focusing on performance, state management thresholds, and modular organization. ## 1. Component Architecture ### 1.1 Standard Component Pattern Every component should follow the standard export pattern to ensure responsiveness (MobX) and performance (Memoization). ```typescript import { observer } from 'mobx-react-lite' const Index = (props: IProps) => { const { data } = props return (
{/* Content */}
) } // ✅ Mandatory: For components needing state responsiveness or performance optimization, use $app.handle wrapper export default new $app.handle(Index).by(observer).by($app.memo).get() // ✅ Optional: For simple presentational components, directly use $app.memo export default $app.memo(Index) ``` ### 1.2 Module Splitting (Fractal Architecture) Large modules must be split according to fractal patterns to maintain high maintainability and clear scope. - **Local Components**: Use `components/` folder within the module directory. Component names should be concise (e.g., `Item.tsx`, `Header.tsx`). - **Loop Extraction**: Components rendered in loops (e.g., content inside `.map()`) must be extracted to separate component files to optimize diff rendering performance. - **File Organization**: ``` module/ ├── index.tsx # Entry and layout ├── types.ts # Local type definitions ├── components/ # Local sub-components │ ├── List.tsx │ ├── Item.tsx # Loop item component extraction │ └── index.ts # Internal unified export ├── models/ # (Optional) Local MobX models │ └── Local.ts └── styles/ # (Optional) CSS Modules └── index.module.css ``` ### 1.3 Props Management Pattern To maintain component cleanliness and reference stability, follow these patterns for declaring and passing Props: - **Performance-sensitive Props**: For props that trigger heavy operations (e.g., Ant Design theme configuration, large data trees), use `useMemo`. - **Standard Props**: If they don't trigger expensive re-renders, simple objects can be declared directly. - **Naming**: Always use `props_*` prefix as the naming convention for internal props objects. ## 2. Performance Optimization ### 2.1 Function Reference Management To prevent unnecessary re-renders of child components, all functions (event handlers, callbacks) must have stable references. ```typescript import { useMemoizedFn } from 'ahooks' // ✅ Mandatory: wrap all component-internal functions with useMemoizedFn const handleClick = useMemoizedFn(() => { // Logic handling }) // ✅ Pass stable references to child components ``` ### 2.2 Props Comparison Optimization `$app.memo` performs deep comparison. To cooperate with its work and avoid unnecessary checks on heavy objects: - **Reference Type Values**: For non-primitive data type props (objects, arrays), use global `$copy(value)` to pass value-based copies. - **Principle**: Using `$copy` ensures that even if the parent component re-renders and creates new object references, as long as the data content hasn't changed, the child component won't re-render. ```typescript // ✅ Mandatory: pass non-primitive data types through $copy ``` ### 2.3 Conditional Style Classes Use the global `$cx` (classix) utility for efficient, readable conditional CSS class merging. ```typescript
``` ## 3. State Management Thresholds ### 3.1 State Hierarchy 1. **Shared State**: Managed by top-level models (e.g., `GlobalModel`), injected via `tsyringe`, obtained using `useGlobal`. 2. **Simple Component State**: If reactive variables/logic blocks are **less than or equal to 4**, manage with standard Hooks (`useState`, `useMemo`). 3. **Complex Component State**: If a component's internal logic exceeds **4 reactive variables**, you must create a standalone MobX model (Local Model) coexisting with that component. ### 3.2 Local Model Implementation Local models also use `tsyringe` dependency injection. ```typescript // module/models/Local.ts import { makeAutoObservable } from 'mobx' import { injectable } from 'tsyringe' @injectable() export class LocalModel { v1 = '' v2 = 0 v3 = [] v4 = false v5 = {} // 5th variable, triggers mandatory Model usage rule constructor() { makeAutoObservable(this, {}, { autoBind: true }) } action() { /* ... */ } } // module/index.tsx const Index = () => { const [local] = useState(() => container.resolve(LocalModel)) return
{local.v1}
} ``` ## 4. Summary Checklist - [ ] Are components exported via `$app.handle` or `$app.memo`? - [ ] Are all component-internal functions wrapped with `useMemoizedFn`? - [ ] Are large object/array props passed using `$copy`? - [ ] Are loop-rendered list items extracted to separate component files? - [ ] Do local component state variables exceed 4? (If yes, transfer to MobX Model) - [ ] Does the directory structure follow fractal patterns?