Components
Don't keep unused code in your components. Keeping dead code around can cause confusion and makes it harder to maintain the codebase. This includes:
Commented out code blocks
Unused imports
Unused props
Unused variables and functions
Dead code paths
Validate the props passed to your component using type aliases or interfaces. This helps to catch bugs early and makes it easier to understand how the component is used. For example:
// Good - using TypeScript interfaces interface UserComponentProps { name: string; age: number; isAdmin?: boolean; } const UserComponent: React.FC<UserComponentProps> = ({ name, age, isAdmin = false }) => { // ... };Make sure you read through a Carbon component's documentation before using it. This helps you to understand the component's props and how to use them. It also helps you to understand the component's behavior and can obviate the need for writing custom code. For example, here's the Button component documentation .
Use keys in lists . This helps React to identify which items have changed, been added, or been removed. This is especially important if you are rendering a list of components that contain state.
Generate keys from the data itself if possible. For example, if you are rendering a list of patients from the database, use the patient's ID as the key. This ensures that the key is unique and stable across renders.
Avoid using effects for things that don't involve synchronizing with external systems. The distinction is nuanced and can be difficult to understand. Please read and internalize the linked article before reaching for effects. Common cases where you don't need to use effects include:
Transforming data for rendering
Handling user events
Updating the UI based on some state
Updating the UI based on a prop change
Scenarios where you do need to use effects include:
Managing subscriptions or WebSocket connections
Controlling non-React widgets that need to be initialized with a DOM element
Managing browser APIs that React doesn't handle for you (e.g. notifications, microphone access, etc.)
Setting up event listeners or other callbacks on window or document objects
When in doubt, ask yourself: "Is this code synchronizing with something outside of React's control?" If not, you probably don't need an effect.
Consider using performance optimizations like
useMemoanduseCallbackin these specific situations:When memoizing expensive computations.
When passing callbacks to optimized child components that rely on referential equality to prevent unnecessary renders.
When creating referentially stable objects or arrays that are used as dependencies in other hooks.
When working with context providers where value changes can trigger widespread re-renders.
Don't treat these hooks as premature optimizations, but rather as tools for specific performance and stability needs. Read the React docs on useMemo and useCallback for detailed guidance.
Omit the value of a prop when it is explicitly
true. For example:// These are equivalent <Button disabled /> // Preferred <Button disabled={true} /> // More verbose, same result
// Be explicit when you need to mark a prop falsy
<Button disabled={false} />// This pattern applies to custom components too
<UserComponent isAdmin /> // Preferred
<UserComponent isAdmin={true} /> // More verbose, same result
<UserComponent isAdmin={false} /> // Must be explicit when falseThis keeps the code cleaner and more maintainable while maintaining full functionality.
Keys can be used to reset the state of a component . This pattern is particularly useful when dealing with forms. When React encounters a component with a different key, it will unmount the old instance and mount a new one, effectively resetting all internal state. Examples of this include:
Forcing a re-render of the UserProfile component when the user switches between profiles:
// Re-render when userId changes <UserProfile key={userId} userId={userId} />Resetting form state when switching between edit modes:
// Can be used to clear all form inputs and validation states <Form key={`${itemId}-${isEditMode}`} item={item} />Resetting an animation instead of transitioning from a previous state:
// Restart animation when count changes <AnimatedNumber key={count} value={count} />
The key principle is: when the key changes, React treats it as a completely different component instance, discarding all previous state. This is cleaner than manually resetting multiple state variables.
Follow consistent code formatting, naming conventions and folder structure. This makes the codebase more readable and easier to maintain.
Provide appropriate dependencies for hooks that accept dependency arrays (
useEffect,useMemo,useCallback,useLayoutEffect,useTransition,useImperativeHandle, anduseDebugValue). This helps ensure that your hooks remain synchronized with the latest props and state of your component. The general rule of thumb is to:Make dependencies as specific as possible while still capturing all values that could affect the hook's behavior
Consider the performance implications of including objects or functions as dependencies
Follow the React documentation guidelines
for managing object and function dependencies
Use the
exhaustive-depsrule fromeslint-plugin-react-hooksto help enforce correct dependency specifications