Category: Performance & Build Tools

Optimizing load times, runtime performance, bundlers (Webpack, Vite), code splitting, caching, and developer tooling configuration.

  • Optimize Next.js Images for Performance

    Optimize Next.js Images for Performance

    Short answer: To optimize Next.js images for performance, use the built-in next/image component, which automatically serves responsive images, lazy loads them, and converts to modern formats like WebP. Configure remote URLs in next.config.js, set appropriate sizes, and use priority for above-the-fold images.

    Key takeaways

    • Always use next/image for automatic optimization.
    • Enable lazy loading for all images by default.
    • Configure remote hostnames in next.config.js.
    • Set explicit width and height to prevent layout shifts.
    • Use priority for above-the-fold images.
    • Serve modern formats like WebP and AVIF.

    Images are often the heaviest assets on a web page. In Next.js, you can optimize images for performance using the built-in next/image component. This component automatically applies lazy loading, responsive sizing, and modern image formats. In this article, you will learn practical steps to optimize Next.js images and improve your site’s speed and user experience.

    Why Image Optimization Matters in Next.js

    Large images slow down page load times and hurt Core Web Vitals, especially Largest Contentful Paint (LCP). Next.js provides the next/image component to handle optimization automatically. It resizes images, serves them in next-gen formats like WebP and AVIF, and lazy loads them by default. This reduces bandwidth usage and improves performance.

    Without optimization, a 2 MB hero image can delay your LCP by several seconds. With next/image, the same image can be served as a 200 KB WebP file, dramatically improving load time.

    A digital illustration of image compression and optimization icons
    Understanding image optimization is key to performance. — Photo: Firmbee / Pixabay

    Getting Started with next/image

    To use the component, import Image from next/image. You can use it for local images stored in your project or remote images from external URLs.

    Using with Local Images

    For local images, just import the file and pass it to the src prop. Next.js automatically optimizes these images.

    import Image from 'next/image';
    import heroImage from '../public/hero.jpg';
    
    export default function Page() {
      return (
        <Image
          src={heroImage}
          alt="Hero image"
          width={1200}
          height={600}
        />
      );
    }
    

    Using with Remote Images

    For remote images, you need to configure the allowed hostnames in next.config.js. This is a security measure.

    // next.config.js
    module.exports = {
      images: {
        remotePatterns: [
          {
            protocol: 'https',
            hostname: 'example.com',
            port: '',
            pathname: '/images/**',
          },
        ],
      },
    };
    

    Then you can use the remote URL in the src prop. Note that you must provide width and height to prevent layout shifts.

    How Lazy Loading Improves Performance

    The next/image component lazy loads images by default. This means images are only loaded when they enter the viewport, saving bandwidth on initial page load. For above-the-fold images, you can disable lazy loading using the priority prop.

    Lazy loading is implemented using the native loading="lazy" attribute and Intersection Observer. It ensures that below-fold images do not block the initial render.

    Setting Responsive Sizes and Breakpoints

    To serve the right image size for each device, use the sizes and fill props. The sizes prop tells the browser how large the image will be at different breakpoints, helping select the best source.

    <Image
      src="/hero.jpg"
      alt="Hero"
      fill
      sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
    />
    

    The fill prop makes the image fill its parent container. You must set the parent to position: relative and define its size.

    A responsive image displayed on different device screens for optimization
    Use responsive sizes to serve the right image for each device. — Photo: gefrorene_wand / Pixabay

    Using Priority for Above-the-Fold Images

    The priority prop tells Next.js to preload the image and skip lazy loading. Use it for the largest above-the-fold image, usually the hero image. This improves LCP because the image starts loading immediately.

    <Image
      src="/hero.jpg"
      alt="Hero"
      width={1200}
      height={600}
      priority
    />
    

    Only use priority for one or two images to avoid overwhelming the network.

    Comparing Image Formats: JPEG vs WebP vs AVIF

    Modern formats like WebP and AVIF provide better compression than JPEG. Next.js automatically negotiates the format based on the browser’s Accept header. You can control this with the formats configuration.

    Format Compression Browser Support Recommended Use
    JPEG Good All Fallback
    WebP Better Widely supported Primary format
    AVIF Best Supported in many modern browsers For supported browsers

    By default, Next.js offers WebP and AVIF. You can customize the allowed formats in next.config.js.

    Additional Optimization Techniques

    Image Caching and CDN

    Next.js caches optimized images in the .next/cache/images directory. For production, consider using a CDN to serve images with cache headers. You can configure custom image loaders to use a CDN like Cloudinary or Imgix.

    Blur Up and Placeholder

    The placeholder prop allows you to show a blurred version of the image while it loads. This improves perceived performance. Use blur for local images or data URL for remote images.

    <Image
      src={heroImage}
      alt="Hero"
      placeholder="blur"
    />
    

    Common Mistakes to Avoid

    Many developers forget to configure remotePatterns for external images, causing errors. Others omit width and height, leading to layout shifts. Avoid using large images without setting sizes, as the browser may download oversized images. Also, do not apply priority to every image; it defeats lazy loading.

    Always test your images with Lighthouse to verify optimization. Check the “Properly size images” audit to see if you serve correctly sized images.

    How to Debug Image Optimization Issues

    When images don’t look right or performance isn’t improving, you can debug using Next.js’s built-in image optimization endpoint. Check the URL of the optimized image: it usually has /_next/image?url=.... If the image is not being optimized, ensure you are using the Image component and not a regular <img> tag. For remote images, verify that the hostname is in remotePatterns and that the image URL is accessible. Use the browser’s network tab to inspect the image request and response headers. Look for content-type to confirm it’s WebP or AVIF. Also check the response status — a 404 means the URL is wrong or the image doesn’t exist.

    Another common issue is that the image size doesn’t match the layout. Use the onLoadingComplete callback to get the actual image dimensions and compare them with what you expect. This helps identify if sizes or width and height are misconfigured.

    Optimizing for Different Screen Sizes and Devices

    To deliver the best experience across mobile, tablet, and desktop, combine the sizes prop with CSS media queries. The sizes attribute tells the browser what width the image will display at each breakpoint. For example, for a full-width hero on mobile and a half-width image on desktop, use sizes="(max-width: 768px) 100vw, 50vw". Always test on real devices to confirm the correct image is downloaded. You can check the image’s “current src” in the browser’s inspector to see which URL the browser selected. If it picks a too-large image, your sizes attribute might be too broad.

    Remember that the Image component generates multiple resized versions of each source image. The default device sizes are: 640, 750, 828, 1080, 1200, 1920, 2048, and 3840 pixels. You can customize these in next.config.js with the imageSizes and deviceSizes options. Adjust them based on your breakpoints and the maximum width of your layout.

    Frequently asked questions

    Does next/image automatically convert images to WebP?

    Yes, the next/image component automatically serves images in WebP and AVIF formats when the browser supports them. It negotiates the format based on the Accept header, so you don’t need to manually convert images.

    Do I need to set width and height for all next/images?

    Yes, you should always set width and height to prevent layout shifts and improve Cumulative Layout Shift (CLS). The only exception is when using the fill prop, where the parent container defines the dimensions.

    How do I use next/image with images from a CMS?

    You can use the remote image approach: configure the CMS domain in remotePatterns in next.config.js, then pass the image URL to the src prop. Ensure you provide width, height, and alt text.

    Can I use next/image with SVG files?

    Yes, but the next/image component does not optimize SVGs because they are vector-based. It will pass the SVG through without resizing or converting formats. You can use an tag or inline instead.

    What is the priority prop and when should I use it?

    The priority prop tells Next.js to preload the image and skip lazy loading. Use it for the largest above-the-fold image (usually the hero) to improve LCP. Avoid using it on multiple images to prevent unnecessary bandwidth usage.

  • Accessibility Checklist for React Applications

    Accessibility Checklist for React Applications

    Short answer: An accessibility checklist for React applications covers semantic HTML, proper ARIA usage, keyboard navigation, focus management, color contrast, form labeling, and automated testing. It helps developers systematically build inclusive web apps that meet WCAG standards.

    Key takeaways

    • Use semantic HTML elements instead of divs.
    • Manage focus order and visible focus indicators.
    • Add ARIA roles only when native semantics are insufficient.
    • Ensure keyboard navigation works for all interactive elements.
    • Test with screen readers and automated tools.
    • Maintain sufficient color contrast ratios.

    Building accessible React applications isn’t just about compliance. It’s about creating experiences that work for everyone, including people who rely on screen readers, keyboard navigation, or magnified displays. Accessibility, often shortened to a11y, should be part of your development workflow from the start. This checklist covers the essential areas you need to address.

    Why Accessibility Matters in React

    React renders dynamic interfaces that can easily break accessibility if you’re not careful. SPA routing, conditional rendering, and complex state changes can confuse assistive technologies. A structured checklist helps you catch issues early and maintain a high standard of usability.

    Accessible apps also benefit search engine SEO and provide a better experience for all users. Many accessibility practices align with good UX principles. By following this checklist, you’ll build more robust and maintainable components.

    Semantic HTML in React Components

    Start by using the correct HTML elements for their intended purpose. Use <nav> for navigation, <main> for primary content, <button> for actions, and <a> for links. Avoid unnecessary <div> or <span> when native elements exist.

    When creating custom components, ensure they render semantic markup. For example, a custom Button component should render a <button> element, not a <div> with an onClick handler. This preserves built-in keyboard and screen reader behavior.

    Use headings (<h1> through <h6>) in a logical order to structure content. Don’t skip levels, and avoid using headings for styling alone. Screen reader users rely on heading structure to navigate pages efficiently.

    One common mistake is using <div> for clickable cards or panels. Instead, consider using a <button> if it triggers an action, or wrap the entire card in an <a> if it navigates. If the card contains multiple actions, structure it with focusable elements inside.

    Developer testing accessibility on a laptop with keyboard and screen reader
    Testing keyboard navigation and screen reader compatibility — Photo: analogicus / Pixabay

    Keyboard Navigation and Focus Management

    All interactive elements must be reachable and operable via keyboard. Use the tab order consistently. Ensure that focus moves in a logical sequence as users tab through the page. Avoid tabindex values greater than 0.

    Manage focus when content changes dynamically. For instance, after a modal opens, move focus to the modal’s first focusable element. When the modal closes, return focus to the triggering button. React’s useRef and lifecycle methods make this manageable.

    Programmatic focus management: use element.focus() after state updates that add new navigation landmarks. For single-page app route changes, announce new content with aria-live regions or move focus to the top of the new view.

    For dynamic lists, such as search results that update as you type, ensure the first result receives focus or is announced. Consider using a useEffect that runs when results change to focus the new list item.

    Visible Focus Indicators

    Never remove the default focus outline without providing a custom visible indicator. Use CSS like :focus-visible to show focus only when navigating by keyboard. Ensure the focus style has a contrast ratio of at least 3:1 against its background.

    Design a focus ring that is noticeable but not overwhelming. A 2px solid outline with a 2px offset works well. Avoid using only color changes, as they may not be visible to users with low vision.

    ARIA Roles, States, and Properties

    ARIA (Accessible Rich Internet Applications) supplements native HTML semantics. Use it sparingly and correctly. The first rule of ARIA is not to use it if you can use a native HTML element that already has the needed semantics.

    When you need ARIA, add roles like role="button" only if the element isn’t naturally a button. For dynamic content, use aria-live regions to announce updates. For example, a live region on a shopping cart icon can announce “Your cart has 3 items” when the count changes.

    Manage ARIA attributes dynamically in React. Use state to toggle aria-expanded on accordion headers, aria-selected on tabs, and aria-hidden on off-screen panels. Ensure that ARIA states match the component’s visual state.

    Be careful with aria-live regions. Use polite for non-critical updates and assertive only for urgent warnings. Overusing assertive can be disruptive. Also, set aria-atomic="true" if the entire region should be announced as a whole.

    Color contrast checker tool on a monitor showing WCAG ratios
    Verifying color contrast ratios for accessible design — Photo: shogun / Pixabay

    Color Contrast and Visual Design

    Text and interactive elements must have sufficient color contrast. The WCAG 2.1 AA standard requires a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text (18px bold or 24px regular). Use tools like the WebAIM Contrast Checker to verify.

    Don’t convey information through color alone. For example, form errors should include an icon or text label, not just a red border. Charts and graphs should use patterns or labels in addition to color.

    Test your design under different color vision deficiencies. Simulators can show how your app looks to users with deuteranopia (red-green color blindness) or other conditions. Aim for clear differentiation without relying on hue.

    For interactive elements like links, use both underline and color to distinguish them from surrounding text. Hover and focus states should also be distinguishable. A good practice is to ensure that the same information is available through text or icons.

    Forms and Input Labels

    Every form input must have an associated label. Use the <label> element with a htmlFor attribute matching the input’s id. Alternatively, wrap the input inside the label. For custom-styled inputs, use aria-label or aria-labelledby.

    Provide clear error messages that are programmatically associated with the input using aria-describedby. For example, a required email field might have an error message like “Please enter a valid email address” linked via aria-describedby="email-error".

    Group related inputs with <fieldset> and <legend>. This is especially useful for radio buttons, checkboxes, and address fields. The legend provides a label for the group, helping screen reader users understand the context.

    For validation, use live regions to announce errors after submission. Avoid relying solely on visual cues. Also, ensure that error messages are concise and actionable, telling the user what to fix.

    Testing Accessibility in React

    Automated testing catches many common issues. Integrate tools like eslint-plugin-jsx-a11y into your IDE and CI pipeline. It flags missing alt text, incorrect ARIA, and invalid heading order. For unit tests, use jest-axe to run accessibility assertions on rendered components.

    Manual testing is equally important. Use your keyboard to navigate the entire app. Can you reach all links, buttons, and form fields? Does the tab order make sense? Also test with a screen reader like NVDA (Windows) or VoiceOver (macOS) to hear what users experience.

    Test on different devices and zoom levels. Ensure the app is usable at high zoom levels and on small screens. Accessibility overlaps significantly with responsive design and mobile usability.

    Create a testing checklist for each new feature. Include items like: “Does this component work with keyboard only?”, “Are focus states visible?”, “Is content announced correctly?” Run manual tests after every major update.

    Images and Alternative Text

    Every image must have appropriate alternative text. Use the alt attribute on <img> elements. For decorative images, set alt="" (empty alt) so screen readers ignore them. For informative images, describe the content concisely.

    In React, always pass an alt prop to your Image component. If the image is a link, the alt text should describe the link destination. For complex images like charts, provide a text alternative nearby or in a longdesc attribute.

    Use ARIA roles like role="img" on SVG icons if they convey meaning. Otherwise, add aria-hidden="true" to ignore them. For icon buttons, combine with aria-label to provide an accessible name.

    Putting It All Together

    Start integrating these checks into your development workflow. Choose a few items from this checklist and focus on them in your next sprint. Over time, accessibility becomes a natural part of your coding habits.

    Remember that accessibility is a continuous process. User needs change, and new tools emerge. Regularly revisit your checklist, run automated scans, and listen to feedback from users with disabilities. Your React app will be better for everyone.

    Frequently asked questions

    What is the most common accessibility mistake in React apps?

    The most common mistake is using unnecessary or incorrect ARIA attributes. Many developers add ARIA roles and properties when a native HTML element already provides the needed semantics. For example, using role=”button” on a <div> instead of using a <button> element. This breaks keyboard navigation and screen reader support.

    How do I manage focus in a single-page React app?

    When navigating between routes, focus should move to the new page’s heading or main content. Use a useEffect hook to call focus() on a ref after the route change. For modals or dialogs, trap focus inside the modal and return it to the trigger element on close. Libraries like react-focus-lock can help.

    Do I always need to use ARIA in React?

    No. The first rule of ARIA is to use native HTML elements when possible. For example, use <button> instead of <div role=”button”>. Use ARIA only when the native semantics are insufficient, such as for live regions, custom widgets, or when you need to overwrite an element’s implicit role.

    What tools can I use to test accessibility in React?

    Use eslint-plugin-jsx-a11y for static analysis in your editor. For unit tests, jest-axe runs Axe accessibility checks on rendered components. For end-to-end testing, tools like Cypress with cypress-axe or Playwright with Axe integration can catch issues during integration tests.

    How often should I run accessibility audits?

    Run automated accessibility checks continuously in your CI pipeline on every pull request. Perform manual keyboard and screen reader tests during feature development and before major releases. Schedule full audits (using tools like Lighthouse or axe DevTools) at least once per sprint or after significant UI changes.

  • Why Your React App Re-renders and How to Fix It

    Why Your React App Re-renders and How to Fix It

    Short answer: React re-renders when state, props, or context change. To fix unnecessary re-renders, use React.memo to memoize components, useMemo and useCallback to stabilize values and functions, and restructure your component tree to avoid broad context updates.

    Key takeaways

    • React re-renders when state, props, or context change.
    • Unnecessary re-renders happen when parent components update child components that don’t need to change.
    • React.memo prevents re-renders if props haven’t changed.
    • useMemo and useCallback stabilize values and functions across renders.
    • Avoiding inline functions and objects in JSX reduces re-renders.
    • Context updates cause all consumers to re-render; split contexts to minimize impact.

    You’ve built a React app that works. But as it grows, you notice it slowing down. Every keystroke lags, and the UI feels sluggish. The culprit is often unnecessary re-renders. In this article, you’ll learn exactly why React re-renders components and how to fix the most common causes. By the end, you’ll have a clear set of tools to make your React app fast and responsive.

    How React Decides to Re-render

    React re-renders a component when its state changes, when its parent re-renders, or when the context it consumes updates. When state changes inside a component, that component re-renders. Then, all its children re-render as well. This cascading behavior is by design: React ensures the UI is always in sync with the data.

    However, this default behavior can cause performance issues. If a parent re-renders, every child re-renders, even if their props haven’t changed. That’s where optimization comes in.

    Common Causes of Unnecessary Re-renders

    A developer looking at a laptop with a frustrated expression, symbolizing performance issues from re-renders
    Unnecessary re-renders can slow down your app. — Photo: Pexels / Pixabay

    Let’s look at the most frequent reasons for too many re-renders in production React apps.

    Inline Functions and Objects in JSX

    When you define a function or create an object directly inside JSX, you create a new reference on every render. For example:

    <Button onClick={() => handleClick(id)} />

    This inline arrow function is a new function every time. If Button is wrapped in React.memo, it will still re-render because the onClick prop reference changes. The same problem applies to inline objects like <Component style={{color: 'red'}} />. A common mistake is to think that React.memo alone solves everything — it doesn’t if you pass new references each time.

    To fix this, extract the inline callback or object outside the JSX, or use useCallback and useMemo to stabilize references. For example, instead of onClick={() => handleClick(id)}, you can define const handleClickCallback = useCallback(() => handleClick(id), [id]); and pass handleClickCallback to the button.

    State Updates That Don’t Change State

    Calling setState with the same value doesn’t cause a re-render in class components, but in functional components using hooks, it does. Every setState call triggers a re-render, even if the value is identical. This is a common source of extra renders when you accidentally update state too frequently, like in an event handler that runs multiple times. A real-world example: a dropdown that opens and closes — if you call setIsOpen(!isOpen) when it’s already open, the state changes and triggers an extra render. Check that you only call state setters when the value actually needs to change.

    Context Re-renders Everything

    When a context provider value changes, every consumer of that context re-renders. If you put too many values in one context, a change to one field triggers re-renders for components that only read the other fields. This is a subtle but major performance drain. To mitigate this, split your context into smaller contexts or use useMemo for the value object so that consumers only re-render when the parts they depend on change.

    For example, if you have a UserContext that holds both userName and theme, a change to theme will re-render components that only read userName. Instead, create separate UserNameContext and ThemeContext providers.

    Tools to Prevent Unnecessary Re-renders

    Diagram showing a tree of components with highlighted nodes indicating re-renders
    Understanding the component tree helps identify re-render patterns. — Photo: 777546 / Pixabay

    React gives you several tools to prevent unnecessary re-renders. Use them wisely — over-optimizing can make your code harder to read.

    Tool Use Case Important Note
    React.memo Prevent re-render of a component when its props haven’t changed. Only shallow-compares props. Use React.memo for pure presentational components that receive simple props. If props contain functions or objects, they must be stable references.
    useMemo Cache a computed value until its dependencies change. Use for expensive calculations, not trivial operations like useMemo(() => a + b, [a, b]) — that adds unnecessary overhead. Reserve it for array transformations, filtering, or complex data manipulations.
    useCallback Return a memoized function reference that only changes when dependencies change. Use when passing callbacks to child components wrapped in React.memo. Always list all dependencies used inside the callback to avoid stale closures.
    useRef Keep a mutable value across renders without causing re-renders. Excellent for timers, DOM references, or any value that changes but shouldn’t trigger a UI update. Unlike state, changing a ref does not trigger a re-render.

    Another important strategy is to lift state down. Instead of putting all state in a high-level component, keep state as close as possible to where it’s used. This reduces the number of components that need to re-render when that state changes. For example, if only one child needs a piece of state, store it in that child instead of the parent. If multiple children need it but not all, consider using a shared context with a granular provider.

    Step-by-Step: Fixing a Common Re-render Problem

    Let’s walk through a typical scenario. You have a parent component that holds a search query and a list of items. The list is filtered based on the query. Without optimization, every keystroke re-renders the entire list.

    1. Identify the problem: Profile your app using React DevTools to see which components re-render. You’ll likely see the list re-rendering on every input change. Open the Profiler tab, start recording, type in the search box, and stop. Look at the flamegraph to spot the list component highlighted as re-rendered.
    2. Memoize the list component: Wrap the list component in React.memo. Now it will only re-render if its props change.
    3. Stabilize the filter function: Use useMemo to compute the filtered list only when the search query or the original list changes. The filtered list reference stays stable if the query didn’t change. Example: const filteredList = useMemo(() => list.filter(item => item.name.includes(query)), [list, query]);
    4. Memoize the filter callback: If you pass a callback to a child, use useCallback to keep the reference stable. This is especially important if the child is wrapped in React.memo. For instance, a delete button inside each list item should receive a stable onDelete function.
    5. Test and profile again: Verify that the list no longer re-renders on unrelated state changes. Use the React DevTools Profiler again to confirm the list component is not re-rendering when only the query changes.

    Common pitfalls: forgetting to include all dependencies in useMemo or useCallback arrays, or wrapping everything in memo without measuring. Always check if the optimization actually reduces re-renders by using the profiler.

    When Not to Optimize

    Optimization has a cost. React.memo adds a prop comparison on every render. useMemo and useCallback add overhead for dependency tracking. Only optimize when you measure a performance problem. Premature optimization can make your code harder to maintain without real benefit.

    A good rule of thumb: focus on components that render often (like list items) or that have expensive render logic (like complex charts). For components that render infrequently or are cheap, let React do its job. Also, avoid wrapping a component in React.memo if it receives children or other JSX — those are objects and always change, defeating the purpose.

    How to Profile Re-renders Effectively

    Before you optimize, you need to know what to fix. Open React DevTools and go to the Profiler tab. Click the record button, interact with your app (like typing in an input), then stop. The profiler shows you all components that re-rendered during that interaction, with timing bars. Look for components that re-render frequently and take a long time. Also, enable the “Record why each component rendered” option to see the reason (state change, parent re-render, context change). This tells you exactly which hook call or prop change caused the re-render.

    Another technique: add console.log statements inside your component to track renders. For example, console.log('MyComponent rendered'). Just remember to remove them in production. This is a low-tech but effective way to spot unnecessary renders.

    For deeper analysis, you can use the why-did-you-render package, but it can be noisy. Only use it on specific components when you need to see why they re-render despite seemingly unchanged props.

    If you’re tackling performance, you might also want to explore lazy loading to reduce initial bundle size. Check out our guide on How to Improve Web Performance with Lazy Loading for techniques that complement re-render optimization.

    Another common issue is accessibility mistakes that accidentally cause re-renders, like using improper ARIA attributes. Read 10 Common Accessibility Mistakes Frontend Developers Make to avoid those pitfalls.

    And if you’re wondering whether React or a framework like Next.js is right for your next project, we compare them in React vs Next.js: Choosing the Right Framework for Your Project.

    Wrapping Up

    Understanding why React re-renders and how to prevent unnecessary ones is key to building performant apps. Start by identifying the worst offenders with React DevTools, then apply React.memo, useMemo, and useCallback where they provide measurable improvement. Always measure before and after. That way, you keep your code clean and your app fast.

    Frequently asked questions

    Does React re-render when props change?

    Yes, when a parent component re-renders, all its children re-render by default, regardless of whether their props have changed. React’s reconciliation algorithm then diffs the virtual DOM, but the re-render function still runs. To prevent this, use React.memo on child components so they only re-render when their props actually change.

    What is the difference between useMemo and useCallback?

    useMemo returns a memoized value from a function, while useCallback returns a memoized function itself. Both accept a dependencies array and only recompute when dependencies change. Use useMemo for expensive computed values, and useCallback when you want to pass a stable function reference to a child component that is wrapped in React.memo.

    Why does my React app re-render on every keystroke?

    This usually happens because your input’s onChange handler updates state in a parent component, causing that parent and all its children to re-render. To fix it, move the state and input logic into a separate component that handles only the input, or use React.memo on the list component to prevent it from re-rendering when the input changes.

    Can context cause unnecessary re-renders?

    Yes. When the value of a context provider changes, every component that consumes that context re-renders, even if they only use a part of the context that didn’t change. To mitigate this, split large contexts into smaller, focused ones, or use useMemo to create the context value so it only changes when necessary.

    Is it always good to use React.memo on every component?

    No. React.memo adds a shallow prop comparison on every render, which has its own cost. It’s best used on components that render often and receive stable props, or on components that have expensive render logic. For lightweight components or those that rarely re-render, the comparison overhead may outweigh the benefit.