ReactJS is a leading library for building dynamic and responsive user interfaces, making it an essential skill for frontend and full-stack developers. Stark.ai offers curated ReactJS interview questions, hands-on challenges, and expert insights to help you stand out in your next interview.
React is a JavaScript library for building user interfaces, particularly single-page applications. It allows developers to create reusable UI components and manage the application's state efficiently.
Components are the building blocks of a React application. They are reusable, independent pieces of UI that can be written as functions or classes, and they accept props as input to produce rendered HTML.
JSX (JavaScript XML) is a syntax extension for JavaScript used in React. It allows you to write HTML elements in JavaScript and place them in the DOM without using `createElement()` or `appendChild()`.
The virtual DOM is a lightweight copy of the real DOM that React uses to track changes. React updates the virtual DOM first and then efficiently updates the real DOM, minimizing direct manipulation and improving performance.
React hooks are functions that allow you to use state and lifecycle features in functional components. Common hooks include `useState`, `useEffect`, `useContext`, and `useRef`.
`useEffect` is a hook that allows you to perform side effects in functional components. It can be used for fetching data, updating the DOM, and setting up subscriptions. It runs after the initial render and optionally after state updates or prop changes.
`useContext` is a hook that allows you to consume context values in functional components. It helps avoid passing props through multiple levels of components by providing a way to share data (like themes or user settings) across the component tree.
Custom hooks in React are functions that allow you to reuse stateful logic across components. They start with the word `use` and can encapsulate complex logic using existing React hooks like `useState` and `useEffect`.
JSX is a syntax extension for JavaScript that allows writing HTML-like code in React. Unlike HTML, JSX uses camelCase properties, requires closing all tags, uses className instead of class, and can directly embed JavaScript expressions using curly braces {}.
Functional components are JavaScript functions that accept props and return JSX, making them simpler and more concise. Class components extend React.Component, can have local state and lifecycle methods, but are generally more verbose. Modern React primarily uses functional components with hooks.
Props are passed as attributes in JSX, similar to HTML attributes. Parent components can pass any JavaScript value (strings, numbers, objects, functions) to child components. Child components receive these props as function parameters or this.props in class components.
Fragments (<React.Fragment> or <>) allow grouping multiple children without adding extra nodes to the DOM. They're useful when you need to return multiple elements from a component without introducing unnecessary wrapper divs, helping maintain clean DOM structure.
JSX supports conditional rendering through: 1) Ternary operators {condition ? elementA : elementB}, 2) Logical && operator for simple conditions {condition && element}, 3) If statements outside the return statement, 4) Extracting conditions to separate methods.
Pure Components (React.PureComponent or React.memo) implement shouldComponentUpdate with a shallow prop and state comparison. They're used to optimize performance by preventing unnecessary re-renders when props or state haven't changed significantly.
Dynamic attributes in JSX use curly braces to embed JavaScript expressions: className={`base ${conditional}`}, style={{property: value}}, or data-attributes={dynamicValue}. Boolean attributes can be set using conditional expressions.
HOCs are functions that take a component and return a new component with additional props or behavior. They're used for code reuse, adding additional functionality like data fetching, authentication, or logging. HOCs follow the pattern: const EnhancedComponent = higherOrderComponent(WrappedComponent).
Lists are rendered using array methods like map(). Each list item must have a unique 'key' prop for React's reconciliation process. Keys should be stable, predictable, and unique among siblings. Using array indices as keys is generally discouraged except for static lists.
Controlled components have their form data controlled by React state, with changes handled through setState. Uncontrolled components store form data in the DOM itself, accessed through refs. Controlled components provide more control but require more code.
Events in JSX use camelCase and pass functions as event handlers: onClick={handleClick}. React uses synthetic events for cross-browser compatibility. Event pooling (pre-React 17) meant event objects were reused for performance, requiring e.persist() for async access.
The children prop represents content between component opening and closing tags. It can be strings, elements, or functions (render props). Access via props.children in functional components or this.props.children in class components. Useful for component composition and reusability.
React.memo is a higher-order component that prevents unnecessary re-renders by memoizing the result. It performs a shallow comparison of props and only re-renders if props have changed. Useful for performance optimization in components with expensive renders.
Portals (ReactDOM.createPortal) allow rendering children into a DOM node outside the parent component's hierarchy. Useful for modals, tooltips, or floating elements that need to break out of parent container limitations while maintaining React context.
Prop validation is handled using PropTypes library for runtime checking. Define propTypes object to specify expected types, required props, and custom validators. In TypeScript, use interface or type definitions for compile-time checking.
Render props is a pattern where a component receives a function as prop that returns React elements. This enables sharing behavior between components by allowing parent components to control what children render while providing them with necessary data or functionality.
Dynamic imports use React.lazy() with Suspense component for code splitting. This allows components to be loaded only when needed: const DynamicComponent = React.lazy(() => import('./Component')). Suspense provides fallback content during loading.
Default exports (export default Component) allow importing with any name but limit one per file. Named exports (export const Component) require exact names or aliases when importing but allow multiple exports per file. Choice affects module organization and refactoring.
React favors composition over inheritance. Use props and children for component customization instead of extending classes. Composition provides more flexibility and clearer data flow. Common patterns include containment and specialization.
Error boundaries are components that catch JavaScript errors in child component tree, log errors, and display fallback UI. They must be class components using componentDidCatch or static getDerivedStateFromError. They don't catch errors in event handlers or async code.
Inline styles in JSX use double curly braces and camelCase properties: style={{backgroundColor: 'blue'}}. Values can be strings or numbers (pixels automatically added). Dynamic styles can use expressions or computed properties.
defaultProps provide default values for props when not specified by parent. Benefits include cleaner code and fail-safe defaults. Drawbacks include potential overhead and less explicit prop requirements. In modern React, consider default parameters for function components.
Functional components use hooks to replicate lifecycle methods: useState for state, useEffect for componentDidMount/Update/Unmount, useLayoutEffect for synchronous effects. This provides more flexible and targeted lifecycle management.
Best practices include: one component per file, grouping related components in folders, separating container and presentational components, using index files for exports, organizing by feature or type, and maintaining consistent naming conventions.
Beyond props, components can communicate through context API, event emitters, state management libraries (Redux/MobX), or custom hooks. Choice depends on scope of communication, app size, and performance requirements.
JSX is syntactic sugar that compiles to React.createElement calls. createElement takes element type, props object, and children as arguments. JSX provides more readable, HTML-like syntax while achieving the same result under the hood.
State can be initialized through useState hook with initial value, lazy initial state function for expensive computations, derived state from props, or custom hooks. Consider performance and whether state is truly needed versus props or computed values.
Reusable components should be generic, well-documented, properly typed, have clear props API, handle edge cases, maintain single responsibility, and be tested thoroughly. Consider composition, prop drilling, and state management needs.
Conditional CSS classes can be handled using template literals, array join methods, or className utilities like classnames library. Example: className={`base ${condition ? 'active' : ''}`} or using object syntax with classnames.
useState is a React hook that adds state to functional components. It returns an array with the current state value and a setter function: const [state, setState] = useState(initialValue). The setter function triggers re-renders when called to update state.
useState is simpler and good for independent pieces of state, while useReducer is better for complex state logic, related state transitions, or when next state depends on previous state. useReducer follows Redux-like patterns with actions and reducers.
React batches multiple state updates in the same synchronous event handler for performance. This means multiple setState calls may be processed in a single re-render. In async operations, use functional updates (prevState => newState) to ensure correct state updates.
Context API provides a way to pass data through the component tree without prop drilling. It's useful for global state like themes, user data, or locale, but shouldn't be used for every state as it can cause unnecessary re-renders.
Always treat state as immutable. Use spread operator or Object.assign() for objects: setState({...state, newProp: value}). For arrays, use methods like map, filter, or spread: setState([...items, newItem]). Never mutate state directly.
Common pitfalls include: mutating state directly, not using functional updates for state depending on previous value, initializing with expensive operations without lazy initialization, and not considering batching behavior in async operations.
State lifting involves moving state to a common ancestor component to share it between components. Implementation requires passing state and setter functions as props. Used when multiple components need to share or modify the same state.
Cleanup functions in useEffect prevent memory leaks and stale state updates by canceling subscriptions or pending operations when component unmounts or dependencies change. Return a cleanup function from useEffect for proper resource management.
Split context into smaller, focused contexts, use React.memo for consumer components, implement value memoization with useMemo, and consider using context selectors. Avoid putting frequently changing values in context.
Custom hooks are reusable functions that encapsulate state logic and can use other hooks. They help abstract complex state management, share stateful logic between components, and follow the DRY principle. Names must start with 'use'.
Form state can be handled using controlled components with useState, formik/react-hook-form libraries for complex forms, or uncontrolled components with refs. Consider validation, submission handling, and error states.
Local state (useState, useReducer) is component-specific and used for UI state. Global state (Context, Redux) is application-wide and used for shared data. Choose based on state scope and component coupling needs.
State persistence can be achieved using localStorage/sessionStorage with useEffect, custom hooks for storage synchronization, or state management libraries with persistence middleware. Consider serialization and hydration strategies.
State machines provide predictable state transitions, clear visualization of possible states, prevent impossible states, and make complex workflows manageable. Libraries like XState help implement state machines in React.
Use multiple state variables for data, loading, and error states. Implement proper error boundaries, loading indicators, and cleanup for cancelled requests. Consider using custom hooks or libraries like react-query for complex data fetching.
Derived state is calculated from existing state/props during render. Use useMemo for expensive calculations. Avoid storing derived values in state; compute them during render to prevent state synchronization issues.
Implement undo/redo using an array of past states and current index. Use useReducer for complex state history management. Consider memory usage and performance implications for large state objects.
Immutability ensures predictable state updates, enables efficient change detection for rendering optimization, prevents bugs from unintended state mutations, and supports time-travel debugging features.
State synchronization can be achieved through lifting state up, using Context API, implementing pub/sub patterns with custom events, or using state management libraries. Consider performance and complexity trade-offs.
Use props directly when possible, implement getDerivedStateFromProps for class components, or use useEffect for functional components. Avoid anti-patterns like copying props to state unless needed for specific use cases.
Use immutable update patterns with spread operator or libraries like immer. Create new object references at each level of nesting. Consider flattening state structure when possible to simplify updates.
Organize state by feature/domain, keep state as close as needed to components, use appropriate mix of local and global state, implement proper state normalization, and document state shape and update patterns.
Use React DevTools to inspect component state, implement logging middleware for state changes, use time-travel debugging in Redux DevTools, and add proper error boundaries and logging for state updates.
Handle initial state hydration, avoid state mismatches between server and client, implement proper state serialization, and consider using state management solutions that support SSR like Redux or Zustand.
Update UI immediately before API confirmation, maintain temporary and permanent state, implement proper rollback mechanisms for failures, and handle race conditions in concurrent updates.
Use custom hooks for reusable state logic, implement higher-order components for state injection, use render props pattern, or leverage Context API for shared state access.
Implement WebSocket connections in useEffect, handle connection lifecycle, update state with incoming messages, and implement proper cleanup. Consider using libraries like Socket.io or custom hooks for WebSocket state.
Use useMemo for expensive computations, implement proper cache invalidation strategies, leverage browser storage for persistence, and consider using caching libraries like react-query for server state.
Use state for controlling animation triggers, implement proper cleanup for animation timeouts, consider using libraries like Framer Motion or React Spring, and handle edge cases during component unmounting.
The three main phases are: Mounting (component is created and inserted into DOM), Updating (component re-renders due to prop or state changes), and Unmounting (component is removed from DOM). Each phase has associated lifecycle methods or hooks.
useEffect combines the functionality of componentDidMount, componentDidUpdate, and componentWillUnmount. The effect runs after render, and its cleanup function (if returned) runs before unmount and before re-running the effect.
componentDidMount executes after the component mounts to the DOM. It's used for initial setup like API calls, subscriptions, or DOM manipulations. In hooks, this is achieved using useEffect with an empty dependency array: useEffect(() => {}, []).
The cleanup function runs before the component unmounts and before every re-render with changed dependencies. It's used to clean up subscriptions, event listeners, or timers to prevent memory leaks. Return a cleanup function from useEffect to implement it.
useEffect runs asynchronously after render completion, while useLayoutEffect runs synchronously before browser paint. useLayoutEffect is used for DOM measurements and mutations that need to be synchronized with rendering to prevent visual flicker.
Use useEffect with appropriate dependency arrays: empty array for mount-only effects, specific dependencies for update effects, no array for every render, and cleanup function for unmount effects. Consider using multiple useEffect hooks to separate concerns.
getDerivedStateFromProps updates state based on prop changes. With hooks, use useEffect to observe prop changes and update state accordingly, but consider if derived state is really needed versus computing values during render.
In class components, use shouldComponentUpdate or extend PureComponent. In functional components, use React.memo for props comparison and useMemo/useCallback to prevent unnecessary re-renders of child components.
Common pitfalls include: missing dependencies leading to stale closures, infinite loops from mutable values, unnecessary re-renders from object/array dependencies, and over-dependency on external values. Use ESLint rules and proper dependency management.
Use componentDidCatch and getDerivedStateFromError in class components for error boundaries. In functional components, use try-catch in event handlers and effects. Consider error boundary components for declarative error handling.
componentWillUnmount handles cleanup before component removal. In hooks, return a cleanup function from useEffect to achieve the same. Use it to remove event listeners, cancel subscriptions, and clear timers to prevent memory leaks.
Both can initiate async operations but require different patterns. Class methods need mounted flags for safety, while hooks can use cleanup functions to cancel pending operations. Consider race conditions and component unmounting.
Constructor initializes state and binds methods in class components. In functional components, useState and useCallback replace these roles. Initial state can be set directly with useState, and function definitions handle method binding.
Use useState with initialization function for expensive computations, useEffect with empty dependency array for setup, and useMemo for computed initial values. Consider lazy initialization patterns to optimize performance.
Set up subscriptions in componentDidMount or useEffect, clean up in componentWillUnmount or effect cleanup function. Handle subscription updates in componentDidUpdate or through effect dependencies. Ensure proper cleanup to prevent memory leaks.
Set up timers in componentDidMount or useEffect, clear them in componentWillUnmount or cleanup function. Use state or refs to track timer IDs. Ensure proper cleanup to prevent memory leaks and unexpected behavior.
Strict mode double-invokes certain lifecycle methods and hooks to help identify side effects. This includes constructor, render, and useEffect. Use it to catch lifecycle-related bugs and ensure proper cleanup implementation.
Use componentDidMount or useLayoutEffect for DOM measurements to ensure the DOM is ready. Store measurements in state or refs. Consider resize observers and window event listeners with proper cleanup.
Use conditional logic inside effects or lifecycle methods, or split into multiple effects with different dependency arrays. Consider extracting complex conditions into separate functions for better maintainability.
Use console logs in lifecycle methods/effects, React DevTools for component mounting/updating visualization, and effect hooks lint rules. Implement proper error boundaries and logging for lifecycle events.
Suspense can interrupt component mounting and trigger fallback rendering. Effects may be delayed or re-run. Consider the implications for data fetching, lazy loading, and error handling in lifecycle methods and effects.
Use componentDidUpdate or useEffect with appropriate dependencies to react to prop changes. Consider memoization with useMemo for derived values and proper dependency array management in effects.
Avoid state updates in render phase. Use componentDidMount/Update or effects for async state updates. Consider batching updates and proper error handling. Be aware of setState's asynchronous nature.
Trigger animations in componentDidMount/Update or useEffect. Handle cleanup in unmount phase. Consider using refs for DOM access and proper timing coordination with React's lifecycle.
Manage focus in componentDidMount/Update or useEffect. Use refs for DOM element access. Consider accessibility implications and proper cleanup of focus-related effects.
Implement preloading in componentDidMount or useEffect with empty dependency array. Consider using Suspense for data fetching and lazy loading. Handle cleanup for abandoned preload requests.
Establish connections in componentDidMount or useEffect, handle reconnection logic in componentDidUpdate or with dependencies, and clean up in componentWillUnmount or effect cleanup. Consider connection state management.
Implement storage updates in effects or lifecycle methods, handle rehydration on mount, and clean up on unmount. Consider using localStorage/sessionStorage with proper serialization and cleanup.
Split effects by concern, manage dependencies independently, consider effect ordering, and implement proper cleanup for each effect. Use custom hooks to encapsulate related effect logic.
The Rules of Hooks are: 1) Only call hooks at the top level (not inside loops, conditions, or nested functions), 2) Only call hooks from React function components or custom hooks. These rules ensure hooks maintain their state and order between renders.
useMemo memoizes a computed value and returns it, while useCallback memoizes a function definition. useMemo is used for expensive calculations, while useCallback is used for function props to prevent unnecessary re-renders of child components.
Custom hooks are functions that use other hooks and must start with 'use' (e.g., useCustomHook). They allow you to extract component logic into reusable functions. Custom hooks can return any values and should follow the Rules of Hooks.
useRef returns a mutable ref object that persists across renders. Common uses include: accessing DOM elements directly, storing previous values, and holding mutable values that don't trigger re-renders. The .current property can be modified without causing re-renders.
useReducer is preferable for complex state logic involving multiple values or when next state depends on previous state. It follows a Redux-like pattern with actions and reducers, making state transitions more predictable and easier to test.
useImperativeHandle customizes the instance value exposed to parent components when using ref. It allows you to control which values and methods are accessible via the ref, enabling better encapsulation of component internals.
Use useMemo for expensive calculations and useCallback for function props passed to optimized child components. Ensure dependency arrays are properly configured. Only use when there's a measurable performance benefit to avoid unnecessary complexity.
useContext subscribes to context changes and returns the current context value. It provides a simpler way to consume context compared to Context.Consumer. Components using useContext will re-render when the context value changes.
Define an async function inside useEffect and call it, or use IIFE. Handle cleanup properly for ongoing operations. Consider race conditions and component unmounting. Don't make the useEffect callback itself async.
useLayoutEffect fires synchronously after DOM mutations but before browser paint. Use it when you need to make DOM measurements or mutations that should be synchronized with rendering to prevent visual flickers.
Create a custom hook that manages form state, validation, submission, and error handling using useState or useReducer. Return form state, handlers, and utility methods. Consider validation timing and form reset functionality.
Create custom hooks that encapsulate the shared logic, state, and side effects. Ensure hooks are generic enough for reuse but specific enough to be useful. Consider composition of multiple hooks for complex logic.
Return cleanup functions from useEffect within custom hooks. Clear timeouts, cancel subscriptions, and remove event listeners. Ensure all resources are properly cleaned up to prevent memory leaks.
useDebugValue adds a label to custom hooks in React DevTools. Use it to display custom hook values for debugging. Consider using the format function parameter to defer expensive formatting until the hook is inspected.
Create a custom hook that adds event listeners in useEffect and removes them in cleanup. Consider debouncing or throttling events, and use useCallback for event handlers to maintain referential equality.
Common pitfalls include: missing dependencies leading to stale closures, unnecessary dependencies causing excess renders, object/array dependencies causing infinite loops, and circular dependencies. Use ESLint rules and proper dependency management.
Create a custom hook that manages page state, items per page, and total pages using useState. Include methods for page navigation and data fetching. Consider caching results and implementing infinite scroll.
Use useCallback and useRef to create a debounced function that delays execution. Clear previous timeout in cleanup. Consider returning both debounced and immediate execution functions.
Since error boundaries must be class components, create a custom hook that works with an error boundary component. Use try-catch in event handlers and effects. Consider implementing retry logic and error logging.
Use useReducer to manage state history array and current index. Implement actions for undo, redo, and new states. Consider memory usage and limiting history size for large state objects.
Create custom hooks for data fetching using useState and useEffect. Handle loading, error, and success states. Consider caching, request cancellation, and retry logic. Use libraries like react-query for complex cases.
Create a custom hook that establishes connection in useEffect, handles message events, and cleans up on unmount. Consider reconnection logic, message queuing, and connection status management.
Create a custom hook that syncs state with localStorage using useEffect. Handle serialization/deserialization, storage events for cross-tab synchronization, and fallbacks for when storage is unavailable.
Create custom hooks for managing auth state, token storage, and user session. Handle login, logout, token refresh, and protected routes. Consider persistent sessions and security implications.
Create a custom hook that manages scroll position, loading state, and data fetching. Use intersection observer or scroll events. Consider data caching, cleanup, and performance optimization.
Create custom hooks for validation logic using useState or useReducer. Handle field-level and form-level validation, async validation, and error messages. Consider validation timing and performance.
Create a custom hook that manages theme state using useState and useContext. Handle theme persistence, dynamic style application, and system preference detection. Consider performance and SSR implications.
Create a custom hook that manages keyboard event listeners using useEffect. Handle key combinations, prevent default behaviors, and clean up listeners. Consider focus management and accessibility.
Use useReducer with a state machine configuration. Define states, transitions, and actions. Consider using libraries like XState. Handle side effects and state persistence.
Props (properties) are read-only data passed from parent to child components. They enable unidirectional data flow, making the application's data flow predictable and easier to debug. Props can include any JavaScript value including functions.
Prop drilling occurs when props are passed through multiple intermediate components that don't need them. Solutions include using Context API, state management libraries like Redux, component composition, or custom hooks to avoid excessive prop passing.
In functional components, use default parameters: function Component({prop = defaultValue}). In class components, use static defaultProps property. Default props ensure components work even when optional props aren't provided.
PropTypes provide runtime type checking for props. They help catch bugs by validating the types and presence of props. Example: Component.propTypes = { name: PropTypes.string.isRequired }. In TypeScript, use interfaces or types instead.
React uses one-way data flow, but two-way binding can be simulated by passing both a value prop and an onChange handler. Common in form inputs: <input value={value} onChange={e => setValue(e.target.value)} />.
Render props are functions passed as props that return React elements. They enable sharing behavior between components: <DataProvider render={data => <Display data={data} />}. This pattern allows for flexible component composition.
In class components, use componentDidUpdate to compare prevProps with current props. In functional components, use useEffect with prop dependencies to react to changes: useEffect(() => { /* handle prop change */ }, [prop]).
children is a special prop that contains the content between component tags. It enables component composition: <Container>{content}</Container>. Can be manipulated using React.Children utilities and supports any valid JSX.
Use PropTypes.shape() for objects, PropTypes.arrayOf() for arrays, and custom validators for complex validation. Example: PropTypes.shape({ id: PropTypes.number, items: PropTypes.arrayOf(PropTypes.object) }).
HOCs are functions that take a component and return an enhanced component. They can manipulate props, add new props, or handle prop-related logic. Important to properly forward props: {...props} to avoid prop isolation.
Use React.memo for functional components or PureComponent for class components to prevent unnecessary re-renders. Implement shouldComponentUpdate for custom comparison. Consider prop structure and reference equality.
Pass event handlers as props using arrow functions or bound methods. Consider performance implications of inline functions. Use callback refs for DOM element access. Maintain proper binding context.
Define interfaces or types for props: interface Props { name: string; age?: number; }. Use them in component definitions: const Component: React.FC<Props> = ({name, age}) => {}. TypeScript provides compile-time type safety.
Context provides a way to pass data through the component tree without explicit prop passing. Useful for global data like themes, user data, or locale. Components can consume context using useContext hook.
Pass loading states and error states as props along with data. Use promises or async/await in parent components. Consider implementing loading skeletons or error boundaries. Handle race conditions in updates.
Use descriptive names, follow consistent conventions, group related props, document prop types and requirements. Consider prop grouping for complex components. Use spread operator judiciously.
Controlled components receive values and handlers as props, while uncontrolled components manage internal state with refs. Choose based on need for form data access and validation requirements.
Compound components are related components that work together sharing implicit state. They often use Context internally while exposing a declarative API through props. Example: <Select><Option value='1'>One</Option></Select>.
Use useEffect to watch for prop changes and trigger animations. Consider using libraries like Framer Motion. Handle cleanup of animation timeouts. Manage transition states properly.
Pass callbacks as props for child-to-parent communication. Use useCallback for memoization. Consider timing of callback execution and cleanup. Handle error cases and loading states.
Prefer computing values during render instead of storing in state. Use useMemo for expensive calculations. If state is needed, update it in useEffect. Consider getDerivedStateFromProps in class components.
Test prop type validation, default props, component rendering with different props, event handlers, and edge cases. Use Jest and React Testing Library. Mock complex props and test error conditions.
Use props in conditional statements, ternary operators, or logical && operator. Handle loading/error states. Consider extract complex conditions to separate functions. Use proper TypeScript types.
Never modify props directly. Create new objects/arrays when updating. Use immutable update patterns or libraries like Immer. Consider performance implications of deep cloning.
Remove PropTypes in production builds for performance. Implement error boundaries for runtime errors. Consider logging prop validation errors. Use TypeScript for compile-time validation.
Transform props in render method or custom hooks. Consider memoization for expensive transformations. Handle edge cases and invalid data. Document transformation logic.
Avoid circular prop passing. Restructure component hierarchy. Consider using Context or state management. Break circular dependencies through component composition.
Use JSDoc comments, PropTypes, or TypeScript interfaces. Document required vs optional props, default values, and examples. Consider using Storybook for interactive documentation.
Use dynamic imports based on props. Implement proper loading states. Handle errors during chunk loading. Consider performance implications and bundle size.
Never expose sensitive data in client-side props. Use proper authentication and authorization. Consider encryption for necessary client-side data. Implement proper cleanup.
Synthetic events are React's cross-browser wrapper around native DOM events. They provide consistent behavior across browsers, follow the W3C spec, and use a pooling mechanism for performance. Access native events via event.nativeEvent property.
Methods include: arrow functions in render, class fields with arrow functions, binding in constructor, or using function components with hooks. Each approach has performance and readability trade-offs. Example: onClick={() => this.handleClick()} or onClick={this.handleClick.bind(this)}.
Event delegation handles events at a higher level in the DOM tree rather than individual elements. React implements this automatically through its event system. Benefits include better memory usage and handling dynamic elements.
Form events (onChange, onSubmit) are handled using controlled components where form data is controlled by React state. Prevent default form submission with e.preventDefault(). Handle validation and submission logic in event handlers.
Use async/await or promises, handle loading and error states, prevent memory leaks with cleanup, consider debouncing/throttling, and handle component unmounting. Example: async handleClick() { try { await apiCall() } catch (error) { handleError() } }
Use stopPropagation() to prevent event bubbling, preventDefault() to prevent default behavior, and capture phase events with onClickCapture. Example: onClick={(e) => { e.stopPropagation(); handleClick(); }}
Custom events can be created using new CustomEvent() and dispatched using dispatchEvent(). In React, prefer prop callbacks or event emitters for component communication. Handle cleanup for custom event listeners.
Use onKeyDown, onKeyPress, onKeyUp events. Check event.key or event.keyCode for specific keys. Consider accessibility, focus management, and keyboard shortcuts. Handle modifier keys (Ctrl, Alt, Shift) appropriately.
Use HTML5 drag and drop events (onDragStart, onDrop, etc.). Implement dataTransfer for data passing. Consider using react-dnd or similar libraries for complex cases. Handle drag preview and drop zones.
Use useCallback for memoized event handlers, useEffect for event listener setup/cleanup, and useState for handling event state. Example: const handleClick = useCallback(() => setState(newValue), [dependencies]).
Handle touchstart, touchmove, touchend events. Consider touch gestures, preventing scroll during touch interactions, and handling multi-touch. Test on various devices and implement fallbacks for desktop.
Use custom hooks or utility functions for debounce/throttle. Consider cleanup on unmount. Example: const debouncedHandler = useDebounce(handler, delay). Handle edge cases and cancellation.
Add listeners to window/document in useEffect, implement proper cleanup, consider context for sharing event handlers, and handle event delegation appropriately. Example: window.addEventListener('resize', handler).
Use input type='file' with onChange event. Access files through event.target.files. Handle multiple files, file validation, progress events, and error cases. Consider using FormData for uploads.
Implement try-catch blocks, use error boundaries for component errors, handle async errors properly, provide user feedback, and log errors appropriately. Consider graceful degradation and recovery.
Use onFocus and onBlur events, manage focus state, implement keyboard navigation, and follow ARIA guidelines. Consider focus trapping for modals and proper tab order.
Use event.stopPropagation() to prevent bubbling, organize handlers hierarchically, consider event delegation, and handle event order carefully. Avoid deeply nested event handling logic.
Use React Testing Library or Enzyme to simulate events, test handler behavior, verify state changes, and check component updates. Mock complex event objects and test error scenarios.
Set up WebSocket connections in useEffect, handle connection events, implement proper cleanup, and manage message events. Consider reconnection logic and error handling.
Create hooks that encapsulate event logic, handle setup/cleanup, manage event state, and provide simple interfaces. Example: useEventListener hook for declarative event handling.
Use throttling or requestAnimationFrame for scroll handlers, consider intersection observer for scroll detection, and implement cleanup properly. Handle scroll position restoration and virtual scrolling.
Use onCopy, onCut, onPaste events, handle clipboard API permissions, implement fallbacks for unsupported browsers, and consider security implications. Handle different data types in clipboard.
Prevent default submission, validate inputs, handle async submission, show loading/error states, and manage form state properly. Consider multi-step forms and partial submissions.
Handle animation start/end events, manage animation state, implement cleanup for interrupted animations, and consider performance. Use requestAnimationFrame for smooth animations.
Handle play, pause, loadeddata, error events for audio/video elements. Implement proper cleanup, manage playback state, and handle loading/buffering. Consider mobile device considerations.
Events bubble up through React's virtual DOM hierarchy regardless of portal placement. Consider event propagation, handle cleanup properly, and manage portal lifecycle.
Handle hydration mismatches, avoid accessing window/document during SSR, implement proper event attachment after hydration, and consider initial state handling.
React 17+ removed event pooling, but understanding includes: using event.persist() for async access in older versions, handling synthetic event limitations, and managing event object lifecycle.
Create custom hooks for intersection observer, handle observer setup/cleanup, manage intersection state, and implement proper threshold configuration. Use for infinite scroll or lazy loading.
A controlled component is one where form data is controlled by React state. Every state change goes through setState, making React the single source of truth. Uncontrolled components store form data in the DOM itself using refs. Controlled components provide more control but require more code.
Use state to store input value and onChange handler to update it: const [value, setValue] = useState(''); return <input value={value} onChange={e => setValue(e.target.value)} />. The component controls the input's value at all times.
Prevent default form submission with e.preventDefault(), validate inputs before submission, handle async submission with loading states, provide user feedback, and implement proper error handling. Consider form state reset after successful submission.
Use an object in state with properties matching input names. Update using computed property names: setState({...formData, [e.target.name]: e.target.value}). Each input's name attribute should match the corresponding state property.
Approaches include: built-in HTML5 validation attributes, custom validation logic in state/handlers, validation libraries like Yup/Joi, form libraries like Formik/React Hook Form. Consider real-time validation vs submission validation.
File inputs are typically uncontrolled. Access files through e.target.files in onChange handler. Use FileReader for preview, FormData for upload. Handle multiple files, validation, and upload progress. Consider drag-and-drop functionality.
Consider debouncing for frequent updates, batch state updates when possible, use memoization for expensive validations, optimize re-renders with proper component structure. Balance real-time validation with performance.
Create components that accept value and onChange props, maintain internal state if needed, properly handle user interactions, and implement proper event handling. Ensure compatibility with form libraries and validation.
Use nested objects in state, implement proper update logic for nested fields, consider using libraries for complex state updates. Example: setState({...form, address: {...form.address, street: value}}). Handle array fields appropriately.
Maintain overall form state across steps, validate each step independently, handle navigation between steps, persist partial data. Consider using reducers for complex state management and proper error handling.
Store errors in state, display field-specific and form-level errors, implement proper error clearing, handle async validation errors. Consider accessibility and user experience in error presentation.
Use localStorage/sessionStorage to save form state, implement auto-save functionality, handle form recovery on page reload. Consider cleaning up saved data and handling version conflicts.
Maintain array of fields in state, implement add/remove field functionality, handle validation for dynamic fields. Consider performance implications and proper state updates for array manipulations.
Use proper HTML form elements, implement proper labeling, handle keyboard navigation, provide error feedback for screen readers. Follow ARIA guidelines and implement proper focus management.
Implement proper reset functionality, handle defaultValue vs value props, consider partial form reset. Handle initialization from props or external data sources. Manage reset for nested and dynamic fields.
Update dependent fields based on other field values, handle validation dependencies, implement proper state updates. Consider performance and user experience in field updates.
Implement debounced validation calls, handle loading states, cache validation results when appropriate. Consider race conditions and cancellation of pending validation requests.
Use FormData for file uploads, handle upload progress, implement proper error handling and retry logic. Consider chunked uploads for large files and proper cleanup of file references.
Test form submission, validation logic, error states, and user interactions. Mock async operations, test accessibility features, and verify form state management. Consider edge cases and error scenarios.
Implement proper label and error message translations, handle different date/number formats, consider right-to-left languages. Use proper localization libraries and handle cultural differences.
Implement debounced save function, handle save states and errors, provide user feedback. Consider conflict resolution and offline capabilities. Handle cleanup of autosave timers.
Implement proper actions and reducers for form state, handle form namespacing, consider performance implications. Balance local vs global state for form data.
Implement virtualization for large lists, optimize validation runs, use proper memoization. Consider chunking large forms and implementing progressive loading.
Handle controlled component behavior, implement proper keyboard navigation, manage dropdown state and positioning. Consider accessibility and mobile device support.
Implement exponential backoff, handle different error types, maintain submission state. Consider user feedback during retries and proper cleanup of retry attempts.
Implement input masks for specific formats, handle cursor position, maintain raw and formatted values. Consider copy/paste behavior and proper validation of masked inputs.
Implement CSRF protection, validate inputs server-side, handle sensitive data properly, prevent XSS attacks. Consider authentication state and proper permissions checking.
Track form interactions, completion rates, error frequencies, and submission patterns. Consider privacy implications and proper data anonymization. Implement proper cleanup of tracking handlers.
Handle initial form state hydration, prevent flash of uncontrolled inputs, implement proper client-side validation initialization. Consider SEO implications and performance optimization.
React Router is a standard routing library for React that enables navigation between views in a React application. It provides components for handling routing declaratively, enabling the creation of single-page applications with multiple views and clean URLs.
BrowserRouter uses HTML5 history API and creates clean URLs (/about), while HashRouter uses URL hash (/#/about). BrowserRouter requires server configuration for direct URL access, while HashRouter works without it but has less clean URLs.
Create a custom Route component that checks authentication status and either renders the protected component or redirects to login. Implement using Route's render prop or a higher-order component pattern.
Switch renders the first Route or Redirect that matches the current location exclusively. It prevents multiple routes from rendering simultaneously and provides exclusive routing.
Use Route path with parameter syntax (:param), access parameters via useParams hook or match.params. Example: <Route path='/user/:id' /> and const { id } = useParams();
Nested routes are routes rendered inside other routes. Implement by nesting Route components or using path composition. Handle proper path matching and component hierarchy.
Use useHistory hook or withRouter HOC. Methods include history.push(), history.replace(), and history.goBack(). Consider state preservation and proper navigation flows.
Use React.lazy and Suspense with React Router to load components dynamically. Implement per-route code splitting for better performance and smaller initial bundle size.
Create a catch-all route at the end of Switch using path='*' or no path prop. Render a 404 component for unmatched routes. Consider user experience and navigation options.
useLocation provides access to the current location object containing pathname, search params, and hash. Useful for accessing query parameters and implementing location-based features.
Use React Transition Group with React Router. Implement enter/exit animations, handle route-based transitions, and manage transition states properly.
exact ensures the path matches exactly the current URL. Without exact, '/users' would match '/users/new'. Use for precise route matching and preventing partial matches.
Use URLSearchParams or custom hooks with useLocation. Parse and manage query parameters, handle updates, and maintain query parameter state.
Use StaticRouter instead of BrowserRouter for SSR. Handle location context, match routes on server, and manage data loading. Consider hydration and state management.
Use route configuration and current location to generate breadcrumbs. Handle dynamic segments, maintain breadcrumb state, and implement proper navigation.
NavLink is a special version of Link that can be styled when it matches the current URL. Useful for navigation menus and indicating active routes.
Implement layout components with nested routes. Handle different layouts per route section, manage common elements, and handle transitions.
useRouteMatch attempts to match the current URL like a Route would. Useful for nested routes and conditional rendering based on route matches.
Implement higher-order components or custom Route components for protection. Handle authentication, authorization, and redirect flows appropriately.
Prompt prevents navigation when certain conditions are met. Used for unsaved form data or pending operations. Implement custom confirmation dialogs.
Implement custom scroll behavior using useEffect. Handle scroll position per route, manage scroll restoration, and implement smooth scrolling.
Route configurations are objects defining route paths, components, and nested routes. Use for centralized route management and dynamic route generation.
Implement React.lazy with prefetching strategies. Handle component preloading, manage loading states, and optimize performance.
MemoryRouter keeps history in memory (not in URL). Useful for testing and non-browser environments. Maintains routing state without URL changes.
Implement data loading in route components or through route handlers. Handle loading states, errors, and data dependencies between routes.
Relative links are paths relative to the current route. Use them for nested navigation and maintaining route hierarchy. Handle proper path resolution.
Use MemoryRouter for testing, mock route matches and history. Test navigation, protected routes, and route parameters. Implement comprehensive test cases.
Implement authentication checks in route components or guards. Handle login flows, session management, and protected route access.
Use React Helmet or similar libraries. Update meta tags per route, handle dynamic content, and manage SEO requirements.
React.memo() is a higher-order component that memoizes component renders based on prop changes. Use it to prevent unnecessary re-renders of functional components when props haven't changed. Best for computationally expensive components.
useMemo memoizes computed values while useCallback memoizes functions. useMemo is used for expensive calculations, while useCallback is used for preventing recreation of function references that might trigger child re-renders.
Code splitting breaks the bundle into smaller chunks loaded on demand. Implement using React.lazy() and Suspense for component-based splitting, or using dynamic import() for route-based splitting.
Use virtualization (react-window or react-virtualized) to render only visible items. Implement windowing, pagination, or infinite scroll. Consider key optimization and memoization for list items.
Use code splitting, tree shaking, dynamic imports, and proper webpack configuration. Remove unused dependencies, implement proper chunking, and analyze bundle with tools like webpack-bundle-analyzer.
Use React.memo for functional components, PureComponent for class components, implement shouldComponentUpdate correctly, and properly structure component hierarchy to minimize prop changes.
Keys help React identify which items have changed, been added, or removed in lists. Proper key usage optimizes reconciliation process and prevents unnecessary DOM operations. Use stable, unique identifiers.
Implement lazy loading, use proper image formats and sizes, implement responsive images, use image CDNs, and consider modern formats like WebP. Implement proper caching strategies.
Context updates can cause all consuming components to re-render. Optimize by splitting context, using memoization, and implementing proper value comparison. Consider alternative state management for frequent updates.
Use Intersection Observer API, implement progressive loading, use lazy loading libraries, or create custom lazy loading components. Handle loading states and fallbacks appropriately.
Inline functions create new function references on every render, potentially causing unnecessary re-renders in child components. Use useCallback or class methods for event handlers in performance-critical scenarios.
Implement route-based code splitting, use proper caching strategies, optimize route matching, and implement proper loading states. Consider preloading routes and route-level data fetching.
Tree shaking eliminates unused code from the final bundle. Configure proper module imports, use ES modules, and ensure proper webpack configuration. Results in smaller bundle sizes and faster load times.
Use controlled components judiciously, implement debouncing for frequent updates, optimize validation timing, and consider uncontrolled components for simple forms. Handle large form state efficiently.
Choose appropriate state management solution, normalize state structure, implement proper selectors, and avoid unnecessary state updates. Consider using immutable data structures.
Minimize DOM mutations, use proper keys for lists, implement batch updates, and avoid direct DOM manipulation. Consider using React.Fragment to reduce DOM nodes.
Web Workers handle CPU-intensive tasks off the main thread. Implement for heavy computations, data processing, and background tasks. Consider using worker-loader or similar tools.
Implement proper caching, use debouncing/throttling, implement request cancellation, and optimize data fetching patterns. Consider using libraries like React Query or SWR.
Use CSS transforms and opacity, implement requestAnimationFrame, avoid layout thrashing, and consider using Web Animations API. Optimize animation frame rate and smooth transitions.
Use functional updates for state depending on previous value, batch updates when possible, and implement proper immutability patterns. Consider using immer or similar libraries.
Keys enable efficient list updates by helping React identify changed items. Use stable, unique identifiers as keys, avoid index as keys for dynamic lists, and ensure proper key propagation.
Analyze library size, implement proper tree shaking, consider alternatives, and load libraries on demand. Use bundle analyzer to identify large dependencies.
Implement CSS-in-JS optimizations, use CSS modules, remove unused styles, and implement proper code splitting for styles. Consider using modern CSS features and optimizing critical CSS.
Use React DevTools Profiler, implement performance metrics collection, monitor key user interactions, and track core web vitals. Consider using performance monitoring tools and analytics.
ErrorBoundaries prevent entire app crashes but can impact performance if overused. Implement strategically, handle errors appropriately, and consider performance implications of error tracking.
Implement proper data fetching strategies, optimize component rendering, implement caching, and handle hydration efficiently. Consider streaming SSR and selective hydration.
Use event delegation, implement proper cleanup, optimize handler reference stability, and consider debouncing/throttling. Handle memory leaks and event listener management.
Choose appropriate data structures, implement proper normalization, use immutable data patterns, and optimize state shape. Consider performance implications of deep nesting.
Use React DevTools effectively for performance profiling, identify unnecessary renders, analyze component updates, and track performance metrics. Implement proper debugging strategies.
Context API provides a way to pass data through the component tree without having to pass props manually at every level. It solves prop drilling issues and enables global state management for specific data that needs to be accessed by many components.
The core components are: React.createContext() to create a context, Context.Provider to wrap components that need access to the context value, and Context.Consumer or useContext hook to consume the context value.
Create context using React.createContext(defaultValue) and provide it using the Provider component: <MyContext.Provider value={value}>{children}</MyContext.Provider>. The value prop can be any JavaScript value.
useContext is a hook that provides a cleaner way to consume context in functional components. Context.Consumer uses render props pattern and is mainly used in class components or when you need to consume multiple contexts in a single component.
Pass functions through context to update values, use state management with context, ensure proper value memoization. Consider performance implications of context updates and implement proper provider structure.
Context triggers re-renders in all consuming components when its value changes. Optimize by splitting contexts, using memoization, and considering component structure. Avoid putting frequently changing values in context.
Create separate contexts for different concerns, nest providers, and consume contexts independently. Consider context composition and proper separation of concerns.
Default value is used when a component consumes context but isn't wrapped in a provider. It's useful for testing, default states, and fallback values. Should represent valid context state.
Use React.memo on consuming components, memoize context value with useMemo, implement proper value comparison. Consider component structure and update patterns.
Context selectors help consume specific parts of context to prevent unnecessary re-renders. Implement using custom hooks, memoization, and proper state structure.
Use static contextType for single context or Context.Consumer for multiple contexts. Access context through this.context or render props pattern.
Use useReducer with Context for complex state management, implement proper action dispatching, handle state updates efficiently. Similar to Redux pattern but lighter weight.
Wrap components in test providers, mock context values, test context updates and consumer behavior. Consider using testing utilities and proper test setup.
Keep context values focused and minimal, separate state and updaters, consider memoization needs. Structure context based on usage patterns and update frequency.
Combine Context with useEffect for async operations, handle loading and error states, implement proper state updates. Consider async patterns and error boundaries.
Compose multiple contexts to separate concerns, improve maintainability, and optimize performance. Use when different parts of the app need different subsets of global state.
Initialize context with meaningful default values, consider lazy initialization, handle initial state properly. Implement proper type checking and documentation.
Overusing context, unnecessary re-renders, improper value memoization, context hell (too many nested providers). Consider alternatives and proper architecture.
Create theme context, provide theme values, implement theme switching, handle dynamic themes. Consider performance and SSR implications.
Use context for form state management, implement proper validation, handle field updates efficiently. Consider form complexity and performance requirements.
Define proper types for context values, use generic types when needed, implement type checking. Consider type safety and proper interface definitions.
Context complements props by providing a way to share values without explicit passing. Use context for truly global state, props for component-specific data.
Implement storage synchronization, handle hydration, manage persistence lifecycle. Consider storage options and state reconciliation.
Store auth state in context, handle auth flows, implement proper security measures. Consider token management and session handling.
Use error boundaries with context, handle error states, implement proper error propagation. Consider error recovery and user feedback.
Use clear naming conventions, organize contexts by feature/domain, implement proper file structure. Consider maintainability and scalability.
Implement proper cleanup in effects, handle unmount scenarios, manage resource disposal. Consider memory leaks and cleanup timing.
Create contexts dynamically, handle context creation lifecycle, manage dynamic providers. Consider performance and maintenance implications.
Document context purpose, value structure, update patterns, and usage examples. Consider documentation maintainability and clarity.
Error Boundaries are React components that catch JavaScript errors in their child component tree and display fallback UI. They prevent the entire app from crashing and provide a way to gracefully handle runtime errors.
Create a class component that implements either getDerivedStateFromError() or componentDidCatch() lifecycle methods. getDerivedStateFromError() renders fallback UI, while componentDidCatch() handles error logging.
Error Boundaries don't catch errors in event handlers, asynchronous code (setTimeout/requestAnimationFrame), server-side rendering, or errors thrown in the error boundary itself. These require different error handling approaches.
Use try-catch blocks in event handlers, implement proper error handling and state updates, provide user feedback. Consider global error handling for uncaught errors in events.
Implement proper error logging services, collect relevant error context, handle different error types appropriately, maintain user privacy. Consider environment-specific logging strategies.
Use try-catch with async/await, implement proper error states, handle promise rejections, use error boundaries where applicable. Consider loading states and user feedback.
componentDidCatch captures error information and error stack traces. Used for error logging, analytics, and side effects in error handling. Cannot modify state during render phase.
Implement retry logic, state reset mechanisms, fallback UI, and proper error clearing. Consider user experience and recovery workflows.
Implement proper error status handling, retry mechanisms, offline detection, and user feedback. Consider caching strategies and fallback content.
Use try-catch in effects, implement error states, handle cleanup properly, consider custom hooks for error handling. Cannot use error boundaries directly in hooks.
Implement client-side validation, handle server validation errors, provide clear error messages, manage error states properly. Consider UX and accessibility.
Implement error reducers, handle async action errors, provide error states in store, consider middleware for error handling. Handle global vs local error states.
Place boundaries strategically to isolate failures, consider component hierarchy, implement granular error handling. Balance between too many and too few boundaries.
Use Error Boundaries with Suspense, handle loading errors, implement fallback UI, manage timeout scenarios. Consider data fetching errors.
Implement error handling logic in HOCs, wrap components with error boundaries, handle prop validation errors. Consider composition of error handling HOCs.
Use error boundaries around portals, handle portal-specific errors, manage cleanup on errors. Consider modal and overlay error scenarios.
Handle app bootstrap errors, implement fallback content, manage configuration errors, provide meaningful error messages. Consider recovery options.
Provide fallback functionality, implement feature detection, handle browser compatibility issues. Consider progressive enhancement approaches.
Implement route-level error boundaries, handle navigation errors, provide error pages, manage route transitions. Consider deep linking errors.
Implement SSR-specific error handling, manage hydration errors, handle state reconciliation issues. Consider client-server error differences.
Provide clear, actionable error messages, implement proper i18n, consider user experience, maintain consistency. Handle different error types appropriately.
Implement proper cleanup in useEffect, handle component unmounting, manage resource disposal. Consider async operation cancellation.
Implement field-level and form-level validation, handle async validation, provide immediate feedback. Consider UX and accessibility requirements.
Implement proper error states, handle network failures, manage retry logic, provide user feedback. Consider caching and offline scenarios.
Implement error tracking services, collect error metrics, analyze error patterns, set up alerts. Consider privacy and performance implications.
Wrap third-party components in error boundaries, handle integration errors, implement fallbacks. Consider version compatibility issues.
Handle session expiration, implement token refresh, manage unauthorized access, provide proper user feedback. Consider security implications.
Integrate error tracking services, collect relevant error data, implement proper error categorization. Consider privacy and compliance requirements.
Test error boundaries, simulate different error conditions, verify error recovery, implement comprehensive test cases. Consider edge cases and error combinations.
Main testing libraries include Jest (test runner and assertion library), React Testing Library (component testing), Enzyme (component testing), Cypress (E2E testing), and React Test Renderer (snapshot testing). Each serves different testing needs and approaches.
React Testing Library is a testing utility that encourages testing components as users would use them. It focuses on testing behavior rather than implementation details, promotes accessibility, and helps write more maintainable tests.
Use async/await with act(), waitFor(), or findBy queries. Handle promises, timers, and API calls properly. Test loading states, success cases, and error scenarios. Consider cleanup and proper test isolation.
Snapshot testing captures a serialized version of component output and compares it against future changes. Useful for detecting unintended UI changes, but should be used carefully to avoid brittle tests.
Use @testing-library/react-hooks with renderHook, test different scenarios and state changes, verify hook behavior and side effects. Consider proper cleanup and isolation.
Simulate events using fireEvent or userEvent, verify handler calls and state changes, test different event scenarios. Consider proper event cleanup and async operations.
Provide test store using Provider, mock store state and actions, test component integration with Redux. Consider proper store setup and cleanup.
Shallow rendering tests component in isolation without rendering child components, while mount rendering fully renders component and children. Each has different use cases and performance implications.
Use MemoryRouter for testing, mock route params and navigation, test route rendering and transitions. Consider history manipulation and location changes.
Test form submissions, validation logic, error states, and user interactions. Use userEvent for form interactions, verify form state and submissions. Consider accessibility testing.
Test component interactions, data flow between components, state management integration. Focus on user workflows and feature completeness. Consider proper test isolation.
Simulate errors to test boundary behavior, verify fallback UI rendering, test error recovery. Consider different error scenarios and component hierarchy.
Wrap components in test providers, test context updates and consumption, verify context-based rendering. Consider proper context setup and cleanup.
Mock external dependencies, API calls, and complex functionality. Use jest.mock() appropriately, maintain mock clarity. Consider partial mocking and mock cleanup.
Use jest-axe for accessibility testing, verify ARIA attributes, test keyboard navigation. Consider screen reader compatibility and accessibility guidelines.
Test animation triggers and completion, verify state changes during transitions, mock timers appropriately. Consider animation cleanup and timing issues.
Test render counts, verify memoization effectiveness, check optimization implementations. Consider performance measurement and monitoring in tests.
Group related tests, maintain clear test structure, use proper naming conventions. Consider test maintainability and readability.
Test useEffect behavior, verify cleanup functions, handle async side effects. Consider proper timing and isolation of side effects.
Mock File API, test upload handlers, verify file validation and processing. Consider different file types and error scenarios.
Use Cypress or Playwright for end-to-end testing, test complete user flows, verify application integration. Consider test stability and maintenance.
Test different render conditions, verify component visibility, check render logic. Consider edge cases and state combinations.
Test portal rendering and content, verify portal functionality and events. Consider DOM structure and cleanup.
Test hook behavior and state changes, verify hook side effects, use appropriate testing utilities. Consider hook lifecycle and cleanup.
Test components with different props and configurations, verify component flexibility and adaptation. Consider edge cases and prop combinations.
Test error scenarios, verify error messages and UI, check error recovery. Consider different types of errors and handling mechanisms.
Test loading states, verify component lazy loading, check suspense fallbacks. Consider network conditions and timing.
Test state updates and transitions, verify state synchronization, check state persistence. Consider complex state scenarios and side effects.
Use tools like Percy or Chromatic, compare visual changes, maintain visual consistency. Consider different viewport sizes and browser compatibility.
Main approaches include: CSS Modules, Styled Components, CSS-in-JS libraries, traditional CSS/SASS, Tailwind CSS, and inline styles. Each approach has different benefits for scoping, maintainability, and performance.
CSS Modules are CSS files where all class names are scoped locally by default. They solve naming conflicts, provide better encapsulation, and enable modular styling. Each component gets unique class names through compilation.
CSS-in-JS is writing CSS code within JavaScript. Advantages include dynamic styling, scoped styles, no global namespace pollution, and better integration with component state. Popular libraries include styled-components and emotion.
Implement theming using CSS variables, styled-components ThemeProvider, or context API. Handle theme switching, maintain consistency, and consider dark mode support. Manage theme variables and inheritance.
Styled Components is a CSS-in-JS library that allows writing actual CSS in JavaScript. Components are created with styles attached, supporting props-based styling, theming, and dynamic styles. Styles are scoped to components.
Use media queries, CSS Grid/Flexbox, responsive units (rem/em), CSS modules for breakpoints, or styled-components media templates. Consider mobile-first approach and component-based responsiveness.
CSS-in-JS can impact runtime performance, CSS Modules have build-time overhead, inline styles prevent browser optimizations. Consider bundle size, runtime performance, and caching strategies.
Use CSS transitions/animations, React Transition Group, Framer Motion, or CSS-in-JS animation props. Consider performance, accessibility, and reduced motion preferences.
Tailwind CSS is a utility-first CSS framework. Integrates through PostCSS, provides utility classes for styling, supports component composition. Requires proper configuration and purging for production.
Use template literals, classnames library, CSS modules composition, or styled-components props. Handle dynamic classes and inline styles based on props or state.
Follow component-based organization, maintain consistent naming conventions, use proper file structure, implement style guide. Consider scalability and maintainability.
Use proper type definitions for styled components, implement theme typing, handle prop types for styled components. Consider type safety and proper inference.
Override styles using CSS specificity, use component APIs for customization, implement wrapper components with custom styles. Consider maintainability and upgrades.
Use global CSS files, styled-components createGlobalStyle, CSS custom properties. Handle reset styles, typography, and theme variables. Consider scope and maintainability.
Implement variant props, use style composition, create style maps/objects. Handle multiple variations and combinations effectively.
Use CSS Modules for scoping, implement proper class naming conventions, manage specificity hierarchy. Consider cascade and inheritance implications.
Implement responsive grid layouts, use grid areas for component placement, handle dynamic grid structures. Consider fallbacks and browser support.
Use CSS logical properties, implement directional styles, handle bidirectional text properly. Consider cultural differences and layout implications.
Implement consistent form styles, handle input states, manage validation styles. Consider accessibility and user feedback.
Implement page transition animations, handle route-based styles, manage transition states. Consider performance and user experience.
Use style props for component customization, implement consistent prop interfaces, handle style composition. Consider type safety and documentation.
Implement critical CSS, handle code splitting, optimize load performance. Consider caching strategies and resource hints.
Handle style extraction, implement proper hydration, manage style injection. Consider performance and flash of unstyled content.
Use CSS variables for dynamic styling, handle theme changes, implement fallbacks. Consider browser support and performance.
Implement progressive enhancement, use appropriate breakpoints, handle touch interactions. Consider device capabilities and constraints.
Implement data-driven styles, handle dynamic classes and properties, manage style updates. Consider performance and maintainability.
Define and manage design tokens, implement token-based styling system, handle theme variations. Consider maintainability and consistency.
Use CSS transitions for subtle animations, implement hover/focus states, handle interaction feedback. Consider performance and accessibility.
Test style rendering, verify theme integration, check dynamic styles. Consider snapshot testing and visual regression testing.
Key principles include: single responsibility, reusability, proper prop drilling avoidance, composition over inheritance, and proper component hierarchy. Components should be small, focused, and maintainable.
Keep state as close as needed to components, use appropriate state management tools (Context, Redux) for global state, implement proper state updates, avoid unnecessary state, and consider state normalization.
Use React.memo for expensive components, implement proper key usage, avoid unnecessary re-renders, use proper dependency arrays in hooks, lazy load components, and implement code splitting.
Use appropriate hooks (useEffect) for side effects, implement proper cleanup, handle async operations correctly, avoid side effects in render, and maintain clear separation of concerns.
Implement error boundaries, handle async errors properly, provide meaningful error messages, implement proper error logging, and maintain graceful degradation of functionality.
Test component behavior not implementation, use proper testing libraries (RTL), implement meaningful assertions, maintain test isolation, and follow testing pyramid principles.
Use prop types or TypeScript, implement proper prop validation, avoid excessive props, use proper prop naming, and consider prop drilling alternatives.
Use controlled components when needed, implement proper validation, handle form state efficiently, manage form submissions properly, and consider form library usage for complex forms.
Organize by feature/domain, maintain clear folder structure, implement proper module boundaries, follow consistent naming conventions, and maintain clear component hierarchy.
Implement proper route organization, handle route guards, implement proper navigation patterns, manage route parameters properly, and consider code splitting by route.
Implement proper data fetching patterns, handle loading and error states, implement caching strategies, maintain proper separation of concerns, and consider API state management.
Follow ARIA guidelines, implement proper keyboard navigation, maintain proper heading hierarchy, provide proper alt texts, and implement proper focus management.
Use appropriate styling solution (CSS Modules, Styled Components), maintain consistent styling patterns, implement proper theme handling, and consider style organization.
Use TypeScript or PropTypes, implement proper type definitions, maintain type consistency, handle type edge cases, and consider type inference optimization.
Use proper state update patterns, handle async state updates correctly, implement proper batching, maintain immutability, and consider state update optimization.
Handle mounting/unmounting properly, implement proper cleanup, manage side effects correctly, handle updates efficiently, and consider performance implications.
Use context appropriately for global state, implement proper provider organization, optimize context updates, avoid context overuse, and consider performance implications.
Implement proper component composition, create reusable hooks, maintain proper abstraction levels, implement proper HOC patterns, and consider code sharing strategies.
Implement proper event handlers, handle event delegation appropriately, manage event cleanup, optimize event binding, and consider event handling patterns.
Prevent XSS attacks, handle sensitive data properly, implement proper authentication/authorization, validate inputs, and consider security implications in data handling.
Implement proper performance metrics, use React DevTools effectively, monitor render performance, track user interactions, and consider performance optimization strategies.
Implement proper lazy loading, use dynamic imports effectively, handle loading states, optimize bundle size, and consider code splitting strategies.
Implement strategic error boundary placement, handle error recovery properly, provide meaningful fallback UI, implement proper error logging, and consider error handling strategies.
Maintain proper dependency versions, handle updates effectively, optimize bundle size, implement proper peer dependencies, and consider dependency management strategies.
Implement proper JSDoc comments, maintain clear prop documentation, document component usage, provide examples, and consider documentation maintenance strategies.
Implement proper i18n solution, handle translations effectively, manage locale changes, consider RTL support, and implement proper internationalization patterns.
Implement proper storage strategies, handle state rehydration, manage persistence lifecycle, consider offline support, and implement proper persistence patterns.
Use React DevTools effectively, implement proper logging, handle error tracking, maintain debugging tools, and consider debugging strategies.
Implement proper fallbacks, handle feature detection, maintain core functionality, consider browser support, and implement proper enhancement strategies.
Implement proper build process, optimize asset delivery, handle environment variables, implement proper CI/CD, and consider deployment strategies.
Common methods include fetch API, Axios, React Query, SWR, GraphQL clients. Each has different features for handling requests, caching, error handling, and request cancellation.
Use useEffect for API calls, handle cleanup with cancel tokens, manage loading and error states, implement proper dependency array. Consider race conditions and component unmounting.
React Query is a data-fetching library that provides caching, background updates, pagination, and optimistic updates. Solves common issues like cache management, loading states, and server state synchronization.
Use try-catch blocks, implement error boundaries, handle different error types, provide user feedback. Consider retry mechanisms and graceful degradation.
Implement proper loading states, handle error cases, manage cache invalidation, consider optimistic updates. Use appropriate state management solutions for API data.
Manage tokens securely, handle token refresh, implement interceptors for requests, manage auth state. Consider session management and security implications.
SWR is a React Hooks library for data fetching that implements stale-while-revalidate strategy. Provides automatic revalidation, focus tracking, and interval polling features.
Use caching libraries (React Query, SWR), implement local storage caching, handle cache invalidation, manage cache lifecycle. Consider cache strategies and freshness.
Implement WebSocket connections, handle Socket.IO integration, manage real-time state updates, handle connection states. Consider reconnection strategies and data consistency.
Handle page state, implement infinite scroll or pagination controls, manage loading states, cache paginated data. Consider optimization and user experience.
Implement request debouncing/throttling, batch requests when possible, optimize payload size, use proper caching strategies. Consider performance and bandwidth usage.
Use FormData, handle upload progress, implement chunk uploads for large files, manage upload states. Consider validation and error handling.
Implement service workers, handle offline storage, manage sync queues, handle conflict resolution. Consider offline-first architecture and data synchronization.
Update UI immediately before API confirmation, handle rollback on failure, manage temporary state, implement proper error recovery. Consider user experience and data consistency.
Implement retry mechanisms, handle different error types appropriately, provide fallback content, manage error states. Consider user feedback and recovery options.
Use AbortController, implement cleanup in useEffect, handle cancel tokens with axios, manage pending requests. Consider race conditions and component lifecycle.
Implement request queuing, handle rate limit errors, manage retry strategies, provide user feedback. Consider backend limitations and optimization strategies.
Use MSW (Mock Service Worker), implement mock data, handle different scenarios, manage mock configurations. Consider testing and development workflow.
Implement proper authentication/authorization, handle CORS, prevent XSS attacks, manage sensitive data. Consider security best practices and vulnerabilities.
Manage API version in configurations, handle version-specific logic, implement proper abstractions. Consider backward compatibility and maintenance.
Implement data normalization, handle response mapping, manage data transformation logic. Consider consistency and maintainability.
Handle sequential requests, manage request priority, implement queue processing logic. Consider error handling and queue management.
Track request times, monitor error rates, implement performance metrics, analyze bottlenecks. Consider monitoring tools and optimization strategies.
Implement exponential backoff, handle retry limits, manage retry states, provide feedback. Consider error types and retry strategies.
Use Apollo Client or other GraphQL clients, manage queries and mutations, handle caching, implement proper error handling. Consider GraphQL-specific optimizations.
Handle authentication headers, manage custom headers, implement interceptors, handle dynamic headers. Consider security and configuration management.
Implement unit tests for API integration, mock API responses, test error scenarios, verify data handling. Consider test coverage and maintenance.
Implement request combining, manage batch processing, handle response correlation, optimize network usage. Consider performance and complexity trade-offs.
Implement local storage caching, handle state rehydration, manage persistence lifecycle. Consider storage strategies and state management.
Handle request/response logging, implement debugging tools, manage log levels, track API usage. Consider privacy and performance implications.
Be fluent in JSX, state management, and the component lifecycle.
Practice creating modular and reusable UI components.
Familiarize yourself with React hooks, Context API, and the latest React features.
Showcase personal or collaborative projects using ReactJS.
Join thousands of successful candidates preparing with Stark.ai. Start practicing ReactJS questions, mock interviews, and more to secure your dream role.
Start Preparing now