[
{
"No": "1",
"Category": "State",
"Guideline": "Use useState for local state",
"Description": "Simple component state should use useState hook",
"Do": "useState for form inputs toggles counters",
"Don't": "Class components this.state",
"Code Good": "const [count, setCount] = useState(0)",
"Code Bad": "this.state = { count: 0 }",
"Severity": "Medium",
"Docs URL": "https://react.dev/reference/react/useState"
},
{
"No": "2",
"Category": "State",
"Guideline": "Lift state up when needed",
"Description": "Share state between siblings by lifting to parent",
"Do": "Lift shared state to common ancestor",
"Don't": "Prop drilling through many levels",
"Code Good": "Parent holds state passes down",
"Code Bad": "Deep prop chains",
"Severity": "Medium",
"Docs URL": "https://react.dev/learn/sharing-state-between-components"
},
{
"No": "3",
"Category": "State",
"Guideline": "Use useReducer for complex state",
"Description": "Complex state logic benefits from reducer pattern",
"Do": "useReducer for state with multiple sub-values",
"Don't": "Multiple useState for related values",
"Code Good": "useReducer with action types",
"Code Bad": "5+ useState calls that update together",
"Severity": "Medium",
"Docs URL": "https://react.dev/reference/react/useReducer"
},
{
"No": "4",
"Category": "State",
"Guideline": "Avoid unnecessary state",
"Description": "Derive values from existing state when possible",
"Do": "Compute derived values in render",
"Don't": "Store derivable values in state",
"Code Good": "const total = items.reduce(...)",
"Code Bad": "const [total, setTotal] = useState(0)",
"Severity": "High",
"Docs URL": "https://react.dev/learn/choosing-the-state-structure"
},
{
"No": "5",
"Category": "State",
"Guideline": "Initialize state lazily",
"Description": "Use function form for expensive initial state",
"Do": "useState(() => computeExpensive())",
"Don't": "useState(computeExpensive())",
"Code Good": "useState(() => JSON.parse(data))",
"Code Bad": "useState(JSON.parse(data))",
"Severity": "Medium",
"Docs URL": "https://react.dev/reference/react/useState#avoiding-recreating-the-initial-state"
},
{
"No": "6",
"Category": "Effects",
"Guideline": "Clean up effects",
"Description": "Return cleanup function for subscriptions timers",
"Do": "Return cleanup function in useEffect",
"Don't": "No cleanup for subscriptions",
"Code Good": "useEffect(() => { sub(); return unsub; })",
"Code Bad": "useEffect(() => { subscribe(); })",
"Severity": "High",
"Docs URL": "https://react.dev/reference/react/useEffect#connecting-to-an-external-system"
},
{
"No": "7",
"Category": "Effects",
"Guideline": "Specify dependencies correctly",
"Description": "Include all values used inside effect in deps array",
"Do": "All referenced values in dependency array",
"Don't": "Empty deps with external references",
"Code Good": "[value] when using value in effect",
"Code Bad": "[] when using props/state in effect",
"Severity": "High",
"Docs URL": "https://react.dev/reference/react/useEffect#specifying-reactive-dependencies"
},
{
"No": "8",
"Category": "Effects",
"Guideline": "Avoid unnecessary effects",
"Description": "Don't use effects for transforming data or events",
"Do": "Transform data during render handle events directly",
"Don't": "useEffect for derived state or event handling",
"Code Good": "const filtered = items.filter(...)",
"Code Bad": "useEffect(() => setFiltered(items.filter(...)))",
"Severity": "High",
"Docs URL": "https://react.dev/learn/you-might-not-need-an-effect"
},
{
"No": "9",
"Category": "Effects",
"Guideline": "Use refs for non-reactive values",
"Description": "Store values that don't trigger re-renders in refs",
"Do": "useRef for interval IDs DOM elements",
"Don't": "useState for values that don't need render",
"Code Good": "const intervalRef = useRef(null)",
"Code Bad": "const [intervalId, setIntervalId] = useState()",
"Severity": "Medium",
"Docs URL": "https://react.dev/reference/react/useRef"
},
{
"No": "10",
"Category": "Rendering",
"Guideline": "Use keys properly",
"Description": "Stable unique keys for list items",
"Do": "Use stable IDs as keys",
"Don't": "Array index as key for dynamic lists",
"Code Good": "key={item.id}",
"Code Bad": "key={index}",
"Severity": "High",
"Docs URL": "https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key"
},
{
"No": "11",
"Category": "Rendering",
"Guideline": "Memoize expensive calculations",
"Description": "Use useMemo for costly computations",
"Do": "useMemo for expensive filtering/sorting",
"Don't": "Recalculate every render",
"Code Good": "useMemo(() => expensive(), [deps])",
"Code Bad": "const result = expensiveCalc()",
"Severity": "Medium",
"Docs URL": "https://react.dev/reference/react/useMemo"
},
{
"No": "12",
"Category": "Rendering",
"Guideline": "Memoize callbacks passed to children",
"Description": "Use useCallback for functions passed as props",
"Do": "useCallback for handlers passed to memoized children",
"Don't": "New function reference every render",
"Code Good": "useCallback(() => {}, [deps])",
"Code Bad": "const handler = () => {}",
"Severity": "Medium",
"Docs URL": "https://react.dev/reference/react/useCallback"
},
{
"No": "13",
"Category": "Rendering",
"Guideline": "Use React.memo wisely",
"Description": "Wrap components that render often with same props",
"Do": "memo for pure components with stable props",
"Don't": "memo everything or nothing",
"Code Good": "memo(ExpensiveList)",
"Code Bad": "memo(SimpleButton)",
"Severity": "Low",
"Docs URL": "https://react.dev/reference/react/memo"
},
{
"No": "14",
"Category": "Rendering",
"Guideline": "Avoid inline object/array creation in JSX",
"Description": "Create objects outside render or memoize",
"Do": "Define style objects outside component",
"Don't": "Inline objects in props",
"Code Good": "<div style={styles.container}>",
"Code Bad": "<div style={{ margin: 10 }}>",
"Severity": "Medium",
"Docs URL": ""
},
{
"No": "15",
"Category": "Components",
"Guideline": "Keep components small and focused",
"Description": "Single responsibility for each component",
"Do": "One concern per component",
"Don't": "Large multi-purpose components",
"Code Good": "<UserAvatar /><UserName />",
"Code Bad": "<UserCard /> with 500 lines",
"Severity": "Medium",
"Docs URL": ""
},
{
"No": "16",
"Category": "Components",
"Guideline": "Use composition over inheritance",
"Description": "Compose components using children and props",
"Do": "Use children prop for flexibility",
"Don't": "Inheritance hierarchies",
"Code Good": "<Card>{content}</Card>",
"Code Bad": "class SpecialCard extends Card",
"Severity": "Medium",
"Docs URL": "https://react.dev/learn/thinking-in-react"
},
{
"No": "17",
"Category": "Components",
"Guideline": "Colocate related code",
"Description": "Keep related components and hooks together",
"Do": "Related files in same directory",
"Don't": "Flat structure with many files",
"Code Good": "components/User/UserCard.tsx",
"Code Bad": "components/UserCard.tsx + hooks/useUser.ts",
"Severity": "Low",
"Docs URL": ""
},
{
"No": "18",
"Category": "Components",
"Guideline": "Use fragments to avoid extra DOM",
"Description": "Fragment or <> for multiple elements without wrapper",
"Do": "<> for grouping without DOM node",
"Don't": "Extra div wrappers",
"Code Good": "<>{items.map(...)}</>",
"Code Bad": "<div>{items.map(...)}</div>",
"Severity": "Low",
"Docs URL": "https://react.dev/reference/react/Fragment"
},
{
"No": "19",
"Category": "Props",
"Guideline": "Destructure props",
"Description": "Destructure props for cleaner component code",
"Do": "Destructure in function signature",
"Don't": "props.name props.value throughout",
"Code Good": "function User({ name, age })",
"Code Bad": "function User(props)",
"Severity": "Low",
"Docs URL": ""
},
{
"No": "20",
"Category": "Props",
"Guideline": "Provide default props values",
"Description": "Use default parameters or defaultProps",
"Do": "Default values in destructuring",
"Don't": "Undefined checks throughout",
"Code Good": "function Button({ size = 'md' })",
"Code Bad": "if (size === undefined) size = 'md'",
"Severity": "Low",
"Docs URL": ""
},
{
"No": "21",
"Category": "Props",
"Guideline": "Avoid prop drilling",
"Description": "Use context or composition for deeply nested data",
"Do": "Context for global data composition for UI",
"Don't": "Passing props through 5+ levels",
"Code Good": "<UserContext.Provider>",
"Code Bad": "<A user={u}><B user={u}><C user={u}>",
"Severity": "Medium",
"Docs URL": "https://react.dev/learn/passing-data-deeply-with-context"
},
{
"No": "22",
"Category": "Props",
"Guideline": "Validate props with TypeScript",
"Description": "Use TypeScript interfaces for prop types",
"Do": "interface Props { name: string }",
"Don't": "PropTypes or no validation",
"Code Good": "interface ButtonProps { onClick: () => void }",
"Code Bad": "Button.propTypes = {}",
"Severity": "Medium",
"Docs URL": ""
},
{
"No": "23",
"Category": "Events",
"Guideline": "Use synthetic events correctly",
"Description": "React normalizes events across browsers",
"Do": "e.preventDefault() e.stopPropagation()",
"Don't": "Access native event unnecessarily",
"Code Good": "onClick={(e) => e.preventDefault()}",
"Code Bad": "onClick={(e) => e.nativeEvent.preventDefault()}",
"Severity": "Low",
"Docs URL": "https://react.dev/reference/react-dom/components/common#react-event-object"
},
{
"No": "24",
"Category": "Events",
"Guideline": "Avoid binding in render",
"Description": "Use arrow functions in class or hooks",
"Do": "Arrow functions in functional components",
"Don't": "bind in render or constructor",
"Code Good": "const handleClick = () => {}",
"Code Bad": "this.handleClick.bind(this)",
"Severity": "Medium",
"Docs URL": ""
},
{
"No": "25",
"Category": "Events",
"Guideline": "Pass event handlers not call results",
"Description": "Pass function reference not invocation",
"Do": "onClick={handleClick}",
"Don't": "onClick={handleClick()} causing immediate call",
"Code Good": "onClick={handleClick}",
"Code Bad": "onClick={handleClick()}",
"Severity": "High",
"Docs URL": ""
},
{
"No": "26",
"Category": "Forms",
"Guideline": "Controlled components for forms",
"Description": "Use state to control form inputs",
"Do": "value + onChange for inputs",
"Don't": "Uncontrolled inputs with refs",
"Code Good": "<input value={val} onChange={setVal}>",
"Code Bad": "<input ref={inputRef}>",
"Severity": "Medium",
"Docs URL": "https://react.dev/reference/react-dom/components/input#controlling-an-input-with-a-state-variable"
},
{
"No": "27",
"Category": "Forms",
"Guideline": "Handle form submission properly",
"Description": "Prevent default and handle in submit handler",
"Do": "onSubmit with preventDefault",
"Don't": "onClick on submit button only",
"Code Good": "<form onSubmit={handleSubmit}>",
"Code Bad": "<button onClick={handleSubmit}>",
"Severity": "Medium",
"Docs URL": ""
},
{
"No": "28",
"Category": "Forms",
"Guideline": "Debounce rapid input changes",
"Description": "Debounce search/filter inputs",
"Do": "useDeferredValue or debounce for search",
"Don't": "Filter on every keystroke",
"Code Good": "useDeferredValue(searchTerm)",
"Code Bad": "useEffect filtering on every change",
"Severity": "Medium",
"Docs URL": "https://react.dev/reference/react/useDeferredValue"
},
{
"No": "29",
"Category": "Hooks",
"Guideline": "Follow rules of hooks",
"Description": "Only call hooks at top level and in React functions",
"Do": "Hooks at component top level",
"Don't": "Hooks in conditions loops or callbacks",
"Code Good": "const [x, setX] = useState()",
"Code Bad": "if (cond) { const [x, setX] = useState() }",
"Severity": "High",
"Docs URL": "https://react.dev/reference/rules/rules-of-hooks"
},
{
"No": "30",
"Category": "Hooks",
"Guideline": "Custom hooks for reusable logic",
"Description": "Extract shared stateful logic to custom hooks",
"Do": "useCustomHook for reusable patterns",
"Don't": "Duplicate hook logic across components",
"Code Good": "const { data } = useFetch(url)",
"Code Bad": "Duplicate useEffect/useState in components",
"Severity": "Medium",
"Docs URL": "https://react.dev/learn/reusing-logic-with-custom-hooks"
},
{
"No": "31",
"Category": "Hooks",
"Guideline": "Name custom hooks with use prefix",
"Description": "Custom hooks must start with use",
"Do": "useFetch useForm useAuth",
"Don't": "fetchData or getData for hook",
"Code Good": "function useFetch(url)",
"Code Bad": "function fetchData(url)",
"Severity": "High",
"Docs URL": ""
},
{
"No": "32",
"Category": "Context",
"Guideline": "Use context for global data",
"Description": "Context for theme auth locale",
"Do": "Context for app-wide state",
"Don't": "Context for frequently changing data",
"Code Good": "<ThemeContext.Provider>",
"Code Bad": "Context for form field values",
"Severity": "Medium",
"Docs URL": "https://react.dev/learn/passing-data-deeply-with-context"
},
{
"No": "33",
"Category": "Context",
"Guideline": "Split contexts by concern",
"Description": "Separate contexts for different domains",
"Do": "ThemeContext + AuthContext",
"Don't": "One giant AppContext",
"Code Good": "<ThemeProvider><AuthProvider>",
"Code Bad": "<AppProvider value={{theme user...}}>",
"Severity": "Medium",
"Docs URL": ""
},
{
"No": "34",
"Category": "Context",
"Guideline": "Memoize context values",
"Description": "Prevent unnecessary re-renders with useMemo",
"Do": "useMemo for context value object",
"Don't": "New object reference every render",
"Code Good": "value={useMemo(() => ({...}), [])}",
"Code Bad": "value={{ user, theme }}",
"Severity": "High",
"Docs URL": ""
},
{
"No": "35",
"Category": "Performance",
"Guideline": "Use React DevTools Profiler",
"Description": "Profile to identify performance bottlenecks",
"Do": "Profile before optimizing",
"Don't": "Optimize without measuring",
"Code Good": "React DevTools Profiler",
"Code Bad": "Guessing at bottlenecks",
"Severity": "Medium",
"Docs URL": "https://react.dev/learn/react-developer-tools"
},
{
"No": "36",
"Category": "Performance",
"Guideline": "Lazy load components",
"Description": "Use React.lazy for code splitting",
"Do": "lazy() for routes and heavy components",
"Don't": "Import everything upfront",
"Code Good": "const Page = lazy(() => import('./Page'))",
"Code Bad": "import Page from './Page'",
"Severity": "Medium",
"Docs URL": "https://react.dev/reference/react/lazy"
},
{
"No": "37",
"Category": "Performance",
"Guideline": "Virtualize long lists",
"Description": "Use windowing for lists over 100 items",
"Do": "react-window or react-virtual",
"Don't": "Render thousands of DOM nodes",
"Code Good": "<VirtualizedList items={items}/>",
"Code Bad": "{items.map(i => <Item />)}",
"Severity": "High",
"Docs URL": ""
},
{
"No": "38",
"Category": "Performance",
"Guideline": "Batch state updates",
"Description": "React 18 auto-batches but be aware",
"Do": "Let React batch related updates",
"Don't": "Manual batching with flushSync",
"Code Good": "setA(1); setB(2); // batched",
"Code Bad": "flushSync(() => setA(1))",
"Severity": "Low",
"Docs URL": "https://react.dev/learn/queueing-a-series-of-state-updates"
},
{
"No": "39",
"Category": "ErrorHandling",
"Guideline": "Use error boundaries",
"Description": "Catch JavaScript errors in component tree",
"Do": "ErrorBoundary wrapping sections",
"Don't": "Let errors crash entire app",
"Code Good": "<ErrorBoundary><App/></ErrorBoundary>",
"Code Bad": "No error handling",
"Severity": "High",
"Docs URL": "https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary"
},
{
"No": "40",
"Category": "ErrorHandling",
"Guideline": "Handle async errors",
"Description": "Catch errors in async operations",
"Do": "try/catch in async handlers",
"Don't": "Unhandled promise rejections",
"Code Good": "try { await fetch() } catch(e) {}",
"Code Bad": "await fetch() // no catch",
"Severity": "High",
"Docs URL": ""
},
{
"No": "41",
"Category": "Testing",
"Guideline": "Test behavior not implementation",
"Description": "Test what user sees and does",
"Do": "Test renders and interactions",
"Don't": "Test internal state or methods",
"Code Good": "expect(screen.getByText('Hello'))",
"Code Bad": "expect(component.state.name)",
"Severity": "Medium",
"Docs URL": "https://testing-library.com/docs/react-testing-library/intro/"
},
{
"No": "42",
"Category": "Testing",
"Guideline": "Use testing-library queries",
"Description": "Use accessible queries",
"Do": "getByRole getByLabelText",
"Don't": "getByTestId for everything",
"Code Good": "getByRole('button')",
"Code Bad": "getByTestId('submit-btn')",
"Severity": "Medium",
"Docs URL": "https://testing-library.com/docs/queries/about#priority"
},
{
"No": "43",
"Category": "Accessibility",
"Guideline": "Use semantic HTML",
"Description": "Proper HTML elements for their purpose",
"Do": "button for clicks nav for navigation",
"Don't": "div with onClick for buttons",
"Code Good": "<button onClick={...}>",
"Code Bad": "<div onClick={...}>",
"Severity": "High",
"Docs URL": "https://react.dev/reference/react-dom/components#all-html-components"
},
{
"No": "44",
"Category": "Accessibility",
"Guideline": "Manage focus properly",
"Description": "Handle focus for modals dialogs",
"Do": "Focus trap in modals return focus on close",
"Don't": "No focus management",
"Code Good": "useEffect to focus input",
"Code Bad": "Modal without focus trap",
"Severity": "High",
"Docs URL": ""
}
]