Refactoring with a Custom Hook

7 min read

Refactoring a complex component is crucial for maintainability and scalability. In this tutorial, we'll refactor the UsersTable component, extracting business logic into a custom hook for better organization and efficiency.

Original UsersTable Component

The UsersTable displays programmer data, including IDs, names, roles, and working hours. It combines data fetching, processing (like calculating total working hours), and UI rendering.

import React, { useState, useEffect, FunctionComponent } from "react";
import type { Role, User } from "@/types";

export const UsersTable: FunctionComponent = () => {
  const [users, setUsers] = useState<User[]>([]);
  const [filteredUsers, setFilteredUsers] = useState<User[]>([]);

  useEffect(() => {
    const fetchUsers = async () => {
      const response = await fetch("/api/users");
      const data = await response.json();
      setUsers(data);
    };

    fetchUsers();
  }, []);

  const filterByRole = (role: Role) => {
    setFilteredUsers(users.filter(user => user.role === role));
  };

  // Total working hours calculation
  const totalWorkingHours = users.reduce(
    (total, user) => total + user.workingHours,
    0
  );

  return <table>{/* Rendering the table */}</table>;
};


Refactoring Step 1: Creating the useUsersTable Custom Hook

import { useState, useEffect } from "react";

export const useUsersTable = () => {
  const [users, setUsers] = useState<User[]>([]);
  const [filteredUsers, setFilteredUsers] = useState<User[]>([]);

  useEffect(() => {
    const fetchUsers = async () => {
      const response = await fetch("/api/users");
      const data = await response.json();
      setUsers(data);
    };

    fetchUsers();
  }, []);

  const calculateTotalWorkingHours = (): number => {
    return users.reduce((total, user) => total + user.workingHours, 0);
  };

  const filterByRole = (role: Role) => {
    setFilteredUsers(users.filter(user => user.role === role));
  };

  return { calculateTotalWorkingHours, filterByRole, filteredUsers };
};

Refactoring Step 2: Update UsersTable component

The custom hook simplifies UsersTable, making it more maintainable and flexible for future feature additions.

import React, { FunctionComponent } from "react";
import useUsersTable from "./useUsersTable";

const UsersTable: FunctionComponent = () => {
	const { filteredUsers, calculateTotalWorkingHours, filterByRole } =
		useUsersTable();

	return <table>{/* Rendering the table with programmers' data */}</table>;
};

Conclusion

Refactoring with custom hooks in React is a powerful strategy for managing complex components. This approach enhances organization, maintainability, and scalability, especially in large-scale applications. Ensure all functionalities are thoroughly tested.