Here’s a React Style Guide, following your specified structure and incorporating all your instructions.
React Style Guide #
External Docs #
Component Guidelines #
General Principles #
- Size Limits: Components should not exceed 200 lines of code. If a component grows beyond this limit, break it down into smaller, more manageable sub-components. This promotes readability, reusability, and easier maintenance.
- Logic Separation: If the JSX structure is not overly complex but the component contains extensive business logic, extract that logic into custom React hooks. This keeps components focused on rendering and makes logic reusable and testable.
- Naming Conventions: All component files should ideally be named using
PascalCase(e.g.,MyComponent.tsx).
File Structure and Organization #
- Common Components: Components that are used across multiple features or pages should be created under the
@componentsalias.- Example:
@components/Button.tsx,@components/Modal.tsx
- Example:
- Feature-Specific Components: Components specific to a particular feature should be nested under
@components/{feature}/component.tsx.- Example:
@components/Auth/LoginForm.tsx,@components/Products/ProductCard.tsx
- Example:
- Page-Specific Components: When adding a new page under
@pages, any components exclusively used by that page should go under@components/{page or feature}/{component}.tsx.- Example: For a
@pages/Dashboard.tsx, its specific components could be@components/Dashboard/Widget.tsx.
- Example: For a
- Cross-Feature Common Components: For components used by more than one feature but not globally, create them under
@components/common/{feature}.tsx.- Example: A reusable table component that might be slightly customized for different features could be
@components/common/Table/GenericTable.tsx.
- Example: A reusable table component that might be slightly customized for different features could be
- Feature-Specific Utilities/Hooks: If a component, utility, or hook is specific to a particular feature, it should be created as part of that feature’s folder instead of global
@hooksor@utils.- Example:
@components/Auth/useAuthForm.ts,@components/Products/productUtils.ts
- Example:
- Index Files for Simplified Imports: When components are nested deeply within feature directories, add an
index.tsfile to re-export components, hooks, and utilities. This allows parent components and pages to use simplified import paths.- Example: Create
@components/Auth/index.tsthat exportsexport { LoginForm } from './LoginForm'; export { useAuth } from './hooks/useAuth';so pages can import withimport { LoginForm, useAuth } from '@components/Auth';
- Example: Create
TypeScript and Type Safety #
- Always use TypeScript: All React components, hooks and functions must be written in TypeScript.
- Proper Typing: Provide explicit and accurate types for all component props. Restrict the usage of
anytype to an absolute minimum, only when no other type can accurately represent the data, and document whyanyis used in such rare cases.
Data Handling #
- API Data Safety: Always handle data coming from APIs with null or optional checks (
?.or??) to prevent UI breaks if data is missing orundefined.- Example:
data?.user?.name ?? 'N/A'
- Example:
- Loading States (Pages): For pages that fetch data from an API, always consider adding a loading state to provide feedback to the user.
- Example: Display a skeleton loader or a “Loading…” message.
- Error Toasts (Pages): When API requests fail on a page, display a user-friendly toast error message to inform the user about the issue.
Handlers #
handlePrefix: All local handlers for events like button clicks or input changes should ideally start with thehandleprefix.- Example:
const handleClick = () => { ... },const handleChange = (event) => { ... }
- Example:
- Prop Handlers: If a handler is received as a prop from a parent component, use the
onClick,onInput,onDoubleClicknaming style for the property name.- Example:
<Button onClick={handleSubmit} />
- Example:
Styling #
- Tailwind CSS Preference: Prefer using Tailwind CSS for all styling needs. This promotes consistency and rapid UI development.
- SCSS for Specifics: If highly specific or complex CSS is required that cannot be efficiently achieved with Tailwind, create a separate SCSS file and import it into the relevant component. Avoid global SCSS unless absolutely necessary for base styles.
Readability and Structure #
- No Empty Spaces in JSX: Avoid adding empty lines or excessive white space within JSX to improve readability and maintain a concise structure.
- Exception: If JSX is hard to read, prefer a component otherwise add an inline comment explaining the code
- Display Names: Always add a
displayNameproperty to your React components. This significantly helps in debugging using React Developer Tools.- Example:
MyComponent.displayName = 'MyComponent';
- Example:
- Inline Functions: Prefer inline functions everywhere for components, hooks, and functions. This approach reduces the number of named functions and keeps the code more concise and readable.
- Example:
const MyComponent = () => <div>Hello World</div>;
- Example:
- Inline Returns for Dumb Components: Dumb components (presentational components that only receive props and render UI) should always use inline return statements. This makes the component’s purpose immediately clear and reduces unnecessary code structure.
- Example:
const Button = ({ children, onClick }: ButtonProps) => <button onClick={onClick}>{children}</button>;
- Example:
Deprecation #
- Mark Old Code: If a component, function, or hook is considered old, no longer actively maintained, or slated for removal, mark it as deprecated. This ensures it’s not accidentally used in new development and signals its eventual removal.
- Example (JSDoc):
/** * @deprecated This component is deprecated. Use <NewComponent /> instead. */ const OldComponent = () => { /* ... */ }; OldComponent.displayName = "OldComponent";
- Example (JSDoc):
Hooks #
- Common Hooks: For hooks used throughout the application (more than one feature on separate pages), create them under the
@hooksalias.- Example:
@hooks/useDebounce.ts,@hooks/useLocalStorage.ts
- Example:
- Feature-Specific Hooks: If a hook is only relevant to a single feature, it should reside within that feature’s directory.
- Example:
@components/Auth/useAuth.ts - Multiple Hooks: If a component requires multiple hooks, organize them under a dedicated
hookssubdirectory within the feature directory.- Example:
@components/Auth/hooks/useAuth.ts,@components/Auth/hooks/useAuthForm.ts,@components/Auth/hooks/useAuthValidation.ts
- Example:
- Example:
API Interaction #
- RTK Query: Always use
rtk-queryfor making API requests. This provides automatic caching, loading states, and error handling out of the box, simplifying data fetching logic.- Define your API slices and endpoints under a dedicated directory, e.g.,
@services/api.ts.
- Define your API slices and endpoints under a dedicated directory, e.g.,
Utilities #
- Common Functions: If there are common functions used in multiple places (more than one feature), keep them under the
@utilsalias.- Example:
@utils/formatDate.ts,@utils/validation.ts
- Example:
- Feature-Specific Utilities: If a utility function is only relevant to a single feature, it should reside within that feature’s directory.
- Example:
@components/Products/productCalculations.ts
- Example:
Constants #
- Centralized Messages: All error messages, success messages, and other string literals that require consistency or might be modified in the future should live inside the
@constantsdirectory. This makes it easy to modify messages globally and ensures a consistent user experience.- Example:
@constants/error-strings.ts,@constants/success-strings.ts
- Example: