Optimizing React APplications

Bundling

The process of combining multiple resources or files into a single unit for easier management, deployment, or distribution.

Bundling

Code splitting

A technique used in software development to split a large bundle of code into smaller, more manageable pieces, which can be loaded dynamically as needed.

CODE SPLITTING

CODE SPLITTING

Import

After

import("./math").then(math => {
  console.log(math.add(16, 26));
});

Before

import { add } from './math';

console.log(add(16, 26));

CODE SPLITTING

React.Lazy

After

onst OtherComponent = React.lazy(() => import('./OtherComponent'));

Before

import OtherComponent from './OtherComponent';

CODE SPLITTING

React.Lazy

import React, { Suspense } from 'react';
import MyErrorBoundary from './MyErrorBoundary';

const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));

const MyComponent = () => (
  <div>
    <MyErrorBoundary>
      <Suspense fallback={<div>Loading...</div>}>
        <section>
          <OtherComponent />
          <AnotherComponent />
        </section>
      </Suspense>
    </MyErrorBoundary>
  </div>
);

Memoization

 Efficiently caching function results for faster execution.

Memoization

React.Memo

const Greeting = memo(function Greeting({ name }) {
  return <h1>Hello, {name}!</h1>;
});

export default Greeting;
const MemoizedComponent = memo(SomeComponent, arePropsEqual?)

useMemo

const visibleTodos = useMemo(
  () => filterTodos(todos, tab),
  [todos, tab]
);
const cachedValue = useMemo(calculateValue, dependencies)

useCallback

const handleSubmit = useCallback((orderDetails) => {
  post('/product/' + productId + '/buy', {
    referrer,
    orderDetails,
  });
}, [productId, referrer]);
const cachedFn = useCallback(fn, dependencies)

Custom Memoization

function memoize(fn) {
  const cache = new Map();
  return function(...args) {
    const key = JSON.stringify(args);
    if (!cache.has(key)) {
      const result = fn(...args);
      cache.set(key, result);
    }
    return cache.get(key);
  };
}

function add(a, b) {
  console.log('Computing sum...');
  return a + b;
}

const memoizedAdd = memoize(add);

console.log(memoizedAdd(2, 3)); // Computes sum... (prints 5)
console.log(memoizedAdd(2, 3)); // (prints 5, result retrieved from cache)
console.log(memoizedAdd(4, 5)); // Computes sum... (prints 9)
console.log(memoizedAdd(4, 5)); // (prints 9, result retrieved from cache)

Memoization Pitfalls

Memoization

When To Use

Memoization

When Not To Use

Virtualization

The idea of rendering only visible rows of content in a dynamic list instead of the entire list.

How VIRTUALIZATION works

VIRTUALIZATION

import React from "react";
import { FixedSizeList } from "react-window";

const data = Array.from({ length: 100000 }, (_, index) => `Item ${index}`);

const renderRow = ({ index, style }) => (
  <div style={{ ...style, display: "flex", alignItems: "center", borderBottom: "1px" }}>
    <span>{data[index]}</span>
  </div>
);

const VirtualizedListExample = () => (
  <div style={{ height: "400px", width: "300px", border: "1px solid lightgrey" }}>
    <FixedSizeList
      height={400}
      width={300}
      itemCount={data.length}
      itemSize={40} // Height of each row
    >
      {renderRow}
    </FixedSizeList>
  </div>
);

export default VirtualizedListExample;

VIRTUALIZATION Libraries

Task

Let's Use the Kanban board for task management from previous task

  • Task 1
    • Display each column in separate routes (i.e: todo, in progress, done)
    • Lazy load every route component
    • Memoize the columns & every item in that list
    • Memoize creating, updating & deleting tasks function
  • Task 2
    • Render 50k plus items in each column
    • Add virtualization to the columns

Deadline: April 22nd, 2024

Optimizing React Applications

By Shamim Fahad

Optimizing React Applications

  • 118