DEV Community

V
V

Posted on

LCP Improvements React Guide

What is LCP?

Largest Contentful Paint (LCP) is a performance metric that measures the time it takes for the largest content element visible in the viewport to fully render on the page. It’s an important user-centric metric for assessing perceived load speed because it marks the point in the page load timeline when the main content has likely loaded and the page is useful to the user. Good LCP performance ensures that a website feels snappy and responsive to users.

Strategies to improve LCP

Avoid unnecessary re-renders by:

  • Correcting the usage of useEffect
  • Doing lazy initialization on useState
  • Using React.memo or useCallBack
  • Avoiding Prop drilling

Improve loading of resources by:

  • Doing code splitting/deferring code
  • Doing lazy loading of components
  • Using srcset for Images

Clean the code by:

  • Removing unused code & Tree Shaking
  • Removing unnecessary CSS
  • Reducing unused exports

UseEffect usage

When to use it:

  • Data Fetching: To fetch data from an API when the component mounts or when a dependency changes.
  • Setting Up Subscriptions: To set up subscriptions (e.g., WebSocket connections) and clean them up when the component unmounts.
  • Manually Updating the DOM: When you need to perform manual DOM updates that can't be done declaratively.

When to avoid it:

  • Derived State: Avoid using useEffect to synchronize state that can be derived from props or other state. Use memoization techniques or derived state directly in the component.
  • Inline Event Handlers: Do not use useEffect to add event listeners that can be added directly in JSX.
  • Rendering Logic: Avoid using useEffect to control rendering logic. Use conditional rendering directly in the JSX.

Lazy Initialization on useState:

Delaying the computation of the initial state value until it is actually needed helps avoid performance hits during the initial render of a component, especially if the computation of the initial state is expensive.
Lazy initialization ensures that this computation is only performed once, when the component is first rendered.

How to Implement Lazy Initialization:

When you pass a function to useState, React will call this function only during the initial render. This ensures that the expensive computation is only done once, and the result is stored as the initial state.

const [state, setState] = useState(() => {
  expensive computation
  return initialValue;
});
Enter fullscreen mode Exit fullscreen mode

React.memo and useCallback

Both React.memo and useCallback are used to optimize React applications by preventing unnecessary re-renders, but they serve different purposes and are used in different scenarios.

useCallback

  • Purpose: useCallback is used to memoize functions.
  • Usage: It returns a memoized version of the callback function that only changes if one of the dependencies has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders.
const memoizedCallback = useCallback(() => {
  // callback logic
}, [dependency1, dependency2]);
Enter fullscreen mode Exit fullscreen mode

useMemo

  • Purpose: useMemo is used to memoize the result of a function.
  • Usage: It returns a memoized value that only changes if one of the dependencies has changed. This is useful for optimizing performance by preventing expensive calculations on every render.
const MyComponent = React.memo(({ prop1, prop2 }) => {
  // Component logic
});
Enter fullscreen mode Exit fullscreen mode

Code Splitting

Code splitting is a technique used to break up a large bundle of JavaScript into smaller, more manageable pieces that can be loaded on demand. This helps improve the initial load time of your application by only loading the necessary code for the initial view and deferring the rest until it's needed. You can also use webpack’s configuration to work with chunks.

Lazy Loading

Lazy loading is a design pattern and optimization technique used to defer the loading of non-critical resources at the time of the page load. Instead, these resources are loaded only when they are needed, such as when they become visible in the viewport or when a user interaction triggers them. This helps improve the performance of web applications by reducing the initial load time and conserving bandwidth.
You can do this by:

  • Use React.lazy for lazy loading React components.
  • Use the Intersection Observer: Use the Intersection Observer API to lazy load images or other elements as they enter the viewport.
const LazyComponent = React.lazy(() => import('./LazyComponent'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <LazyComponent />
    </Suspense>
  );
}
Enter fullscreen mode Exit fullscreen mode

Use native capabilities

  • Images attributes: the srcset attribute allows you to specify multiple image sources for different screen sizes and resolutions. The browser automatically selects the most appropriate image to display based on the device's characteristics. This can significantly improve the Largest Contentful Paint (LCP) by ensuring that the optimal image size is loaded, reducing load times and improving performance. On the other hand, the sizes attribute tells the browser how much space the image will take up, allowing it to choose the best source.
<img
  src="images/example-300.jpg"
  srcset="
    images/example-300.jpg 300w,
    images/example-600.jpg 600w,
    images/example-1200.jpg 1200w
  "
  sizes="
    (max-width: 600px) 300px,
    (max-width: 1200px) 600px,
    1200px
  "
  alt="Description of the image"
/>
Enter fullscreen mode Exit fullscreen mode
  • Loading attribute: The loading attribute on images and iframes allows for native lazy loading.
<img src="image.jpg" alt="Example image" loading="lazy">
<iframe src="https://example.com" loading="lazy"></iframe>
Enter fullscreen mode Exit fullscreen mode
  • Rel property: preload: Preloading critical resources can improve LCP by ensuring that key assets are fetched as soon as possible. Preloading CSS and JavaScript files ensures that these assets are available immediately when the browser starts rendering the page. Preloading fonts can prevent delays caused by font loading, which can block text rendering.
<link rel="preload" href="/styles/main.css" as="style">
<link rel="preload" href="/scripts/main.js" as="script">
<link rel="preload" href="/fonts/font.woff2" as="font" type="font/woff2" crossorigin="anonymous">
Enter fullscreen mode Exit fullscreen mode

prefetch: Next Page Resources: Prefetch resources that are needed for the next user interaction to improve the perception of a fast-loading application.

<link rel="prefetch" href="/images/next-page-image.jpg">
Enter fullscreen mode Exit fullscreen mode
  • Script attributes:

Defer the loading of JavaScript that is not critical for the initial render by adding the defer attribute in your script tags. This ensures that the script is executed after the HTML is parsed, preventing it from blocking the rendering process.

<script src="script.js" defer></script>
Enter fullscreen mode Exit fullscreen mode

Async Loading: Allows the script to be fetched in parallel to parsing and executed as soon as it is available, reducing render-blocking behavior.

<script src="script.js" async></script>
Enter fullscreen mode Exit fullscreen mode

Top comments (0)