Performance is a crucial factor in React application development. In this article, we’ll explore techniques and best practices to optimize performance.

1. React.memo()

React.memo() helps prevent unnecessary re-renders:

import React, { memo } from "react";

const ExpensiveComponent = memo(({ data }) => {
  console.log("Component rendered");

  return (
    <div>
      <h2>{data.title}</h2>
      <p>{data.description}</p>
    </div>
  );
});

// Component only re-renders when props change
export default ExpensiveComponent;

2. useMemo Hook

Use useMemo for expensive calculations:

import React, { useMemo } from "react";

function ProductList({ products, searchTerm }) {
  const filteredProducts = useMemo(() => {
    return products.filter((product) =>
      product.name.toLowerCase().includes(searchTerm.toLowerCase()),
    );
  }, [products, searchTerm]);

  const expensiveCalculation = useMemo(() => {
    return filteredProducts.reduce((sum, product) => sum + product.price, 0);
  }, [filteredProducts]);

  return (
    <div>
      <p>Total Price: {expensiveCalculation}</p>
      {filteredProducts.map((product) => (
        <div key={product.id}>
          {product.name} - ${product.price}
        </div>
      ))}
    </div>
  );
}

3. useCallback Hook

Optimize event handlers:

import React, { useState, useCallback } from "react";

function TodoList() {
  const [todos, setTodos] = useState([]);

  const addTodo = useCallback((text) => {
    setTodos((prev) => [...prev, { id: Date.now(), text, completed: false }]);
  }, []);

  const toggleTodo = useCallback((id) => {
    setTodos((prev) =>
      prev.map((todo) =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo,
      ),
    );
  }, []);

  return (
    <div>
      <TodoForm onAdd={addTodo} />
      {todos.map((todo) => (
        <TodoItem key={todo.id} todo={todo} onToggle={toggleTodo} />
      ))}
    </div>
  );
}

4. Code Splitting

Split code for faster loading:

import React, { Suspense, lazy } from "react";

// Lazy load components
const Dashboard = lazy(() => import("./Dashboard"));
const Profile = lazy(() => import("./Profile"));

function App() {
  return (
    <Router>
      <Suspense fallback={<div>Loading...</div>}>
        <Routes>
          <Route path="/dashboard" element={<Dashboard />} />
          <Route path="/profile" element={<Profile />} />
        </Routes>
      </Suspense>
    </Router>
  );
}

5. Virtualization

Use virtualization for long lists:

import { FixedSizeList as List } from "react-window";

const Row = ({ index, style, data }) => (
  <div style={style}>
    <div>Item {data[index].name}</div>
  </div>
);

function VirtualizedList({ items }) {
  return (
    <List height={400} itemCount={items.length} itemSize={50} itemData={items}>
      {Row}
    </List>
  );
}

6. Image Optimization

Optimize images:

function OptimizedImage({ src, alt, ...props }) {
  return (
    <img
      src={src}
      alt={alt}
      loading="lazy"
      decoding="async"
      {...props}
      style={{
        ...props.style,
        aspectRatio: "16/9",
        objectFit: "cover",
      }}
    />
  );
}

Best Practices

1. Avoid inline objects and functions

// ❌ Avoid
function Component() {
  return (
    <Child style={{ marginTop: 10 }} onClick={() => console.log("clicked")} />
  );
}

// ✅ Better
const styles = { marginTop: 10 };
const handleClick = () => console.log("clicked");

function Component() {
  return <Child style={styles} onClick={handleClick} />;
}

2. Use keys properly

// ❌ Avoid using index
{
  items.map((item, index) => <Item key={index} data={item} />);
}

// ✅ Use unique identifier
{
  items.map((item) => <Item key={item.id} data={item} />);
}
import { useDeferredValue } from "react";

function SearchResults({ query }) {
  const deferredQuery = useDeferredValue(query);
  const results = useMemo(() => searchAPI(deferredQuery), [deferredQuery]);

  return <ResultsList results={results} />;
}

Conclusion

Optimizing React performance requires:

  • Understanding lifecycle and rendering process
  • Using React hooks correctly
  • Applying appropriate optimization techniques
  • Regular performance monitoring and measuring

Remember that “premature optimization is the root of all evil” - only optimize when truly necessary! 🚀