useHooks.iov4.1.2
DocsBlogGitHub

Building Better React Apps: A Hands-on Guide to usehooks-cli

Learn how to supercharge your React development workflow with usehooks-cli through this practical, step-by-step tutorial.

By usehooks.io

reacthooksclitutorialproductivity

Custom hooks are one of React's most powerful features, but managing them across projects can be challenging. In this hands-on tutorial, we'll explore how usehooks-cli can transform your development workflow by making it effortless to discover, add, and maintain React hooks in your projects.

What You'll Learn

By the end of this tutorial, you'll know how to:

  • Set up usehooks-cli in your React project
  • Find and add the perfect hooks for your needs
  • Update and maintain hooks across your codebase
  • Integrate hooks with your components
  • Manage hook dependencies efficiently

Prerequisites

  • Node.js 18.0.0 or higher
  • A React project (Next.js, Vite, Create React App, etc.)
  • Basic familiarity with React hooks

Step 1: Setting Up Your Project

Let's start by initializing usehooks-cli in your React project. There's no need to install anything globally—we'll use npx to run the CLI directly:

1npx usehooks-cli@latest init
2

This command will:

  1. Detect your project structure (Next.js, Vite, CRA, etc.)
  2. Suggest optimal locations for your hooks directory
  3. Create a configuration file (usehooks.json) with your preferences

You'll be prompted to answer a few questions about your project setup:

The CLI is smart enough to detect your project structure and suggest sensible defaults, but you can customize these settings as needed.

Step 2: Discovering Available Hooks

Before adding hooks to your project, let's explore what's available. usehooks-cli provides several ways to discover hooks:

Browsing All Hooks

To see a complete list of available hooks organized by category:

1npx usehooks-cli@latest list
2

You'll see output similar to this:

1Available hooks:
2
3STATE
4● use-array
5  A hook providing helper methods for working with array state including push, pop, filter, sort, and other common operations
6● use-counter
7  A hook for managing counter state with increment, decrement, and reset
8● use-local-storage
9  A hook for managing localStorage with React state
10● use-set
11  A hook for managing and manipulating Set data structure with comprehensive methods for set operations, filtering, and state management
12● use-toggle
13  A hook for managing toggle state with toggle and reset
14

Searching for Specific Hooks

If you have a specific need in mind, you can search for relevant hooks:

1npx usehooks-cli@latest search "form"
2

This will find all hooks related to form handling, showing matches in names, descriptions, and categories.

Step 3: Adding Your First Hook

Let's add a hook to your project. For this tutorial, we'll use the popular use-local-storage hook, which provides a useState-like API that persists data in localStorage:

1npx usehooks-cli@latest add use-local-storage
2

The CLI will:

  1. Download the hook from the registry
  2. Add it to your hooks directory
  3. Install any required dependencies
  4. Provide confirmation when complete

Step 4: Using the Hook in Your Component

Now that you've added the hook, let's use it in a component. Create or modify a component file:

1import { useLocalStorage } from "../hooks/useLocalStorage";
2
3function UserPreferences() {
4  const [theme, setTheme] = useLocalStorage<"light" | "dark">("theme", "light");
5  const [fontSize, setFontSize] = useLocalStorage<number>("fontSize", 16);
6
7  return (
8    <div className={`theme-${theme}`}>
9      <h2>User Preferences</h2>
10
11      <div>
12        <label>
13          <input
14            type="checkbox"
15            checked={theme === "dark"}
16            onChange={() => setTheme(theme === "light" ? "dark" : "light")}
17          />
18          Dark Mode
19        </label>
20      </div>
21
22      <div>
23        <label>Font Size: {fontSize}px</label>
24        <input
25          type="range"
26          min="12"
27          max="24"
28          value={fontSize}
29          onChange={(e) => setFontSize(Number(e.target.value))}
30        />
31      </div>
32    </div>
33  );
34}
35

This component uses the useLocalStorage hook to persist user preferences across page refreshes and browser sessions.

Step 5: Getting Detailed Information About a Hook

To learn more about how a hook works and see examples of its usage:

1npx usehooks-cli@latest info use-local-storage
2

Step 6: Adding Multiple Hooks at Once

As your project grows, you might need multiple hooks. You can add several hooks in one command:

1npx usehooks-cli@latest add use-counter use-debounce use-media-query
2

Alternatively, you can use interactive selection mode by running the command without arguments:

1npx usehooks-cli@latest add
2

This will present a checklist of all available hooks, allowing you to select multiple hooks to add at once.

Step 7: Keeping Your Hooks Up-to-Date

As the usehooks.io library evolves with bug fixes and improvements, you'll want to keep your hooks updated. To check for and apply updates:

1npx usehooks-cli@latest update --all
2

The CLI will:

  1. Compare your installed hooks with the latest versions
  2. Create backups of your current hooks
  3. Apply updates where available
  4. Install any new dependencies

Step 8: Removing Hooks You No Longer Need

If you decide you no longer need a hook, you can remove it cleanly:

1npx usehooks-cli@latest remove use-counter --clean-deps
2

The --clean-deps flag will also remove any dependencies that were installed specifically for this hook and aren't used elsewhere in your project.

Real-World Project Example: Building a Task Manager

Let's put everything together by building a simple task manager application that uses multiple hooks:

  1. First, add the hooks we'll need:
1npx usehooks-cli@latest add use-local-storage use-boolean use-debounce
2
  1. Create a TaskManager component:
1import { useLocalStorage } from "../hooks/useLocalStorage";
2import { useBoolean } from "../hooks/useBoolean";
3import { useDebounce } from "../hooks/useDebounce";
4import { useState } from "react";
5
6interface Task {
7  id: string;
8  text: string;
9  completed: boolean;
10}
11
12function TaskManager() {
13  // Persist tasks in localStorage
14  const [tasks, setTasks] = useLocalStorage<Task[]>("tasks", []);
15
16  // UI state
17  const [newTaskText, setNewTaskText] = useState("");
18  const [searchText, setSearchText] = useState("");
19  const [showCompleted, toggleShowCompleted] = useBoolean(true);
20
21  // Debounce search to improve performance
22  const debouncedSearchText = useDebounce(searchText, 300);
23
24  // Filter tasks based on search and completion status
25  const filteredTasks = tasks.filter((task) => {
26    const matchesSearch = task.text
27      .toLowerCase()
28      .includes(debouncedSearchText.toLowerCase());
29    const matchesCompletion = showCompleted || !task.completed;
30    return matchesSearch && matchesCompletion;
31  });
32
33  // Add a new task
34  const addTask = () => {
35    if (newTaskText.trim() === "") return;
36
37    setTasks([
38      ...tasks,
39      {
40        id: Date.now().toString(),
41        text: newTaskText,
42        completed: false,
43      },
44    ]);
45
46    setNewTaskText("");
47  };
48
49  // Toggle task completion
50  const toggleTask = (id: string) => {
51    setTasks(
52      tasks.map((task) =>
53        task.id === id ? { ...task, completed: !task.completed } : task
54      )
55    );
56  };
57
58  // Remove a task
59  const removeTask = (id: string) => {
60    setTasks(tasks.filter((task) => task.id !== id));
61  };
62
63  return (
64    <div className="task-manager">
65      <h1>Task Manager</h1>
66
67      {/* Add new task */}
68      <div className="add-task">
69        <input
70          type="text"
71          value={newTaskText}
72          onChange={(e) => setNewTaskText(e.target.value)}
73          placeholder="Add a new task..."
74        />
75        <button onClick={addTask}>Add</button>
76      </div>
77
78      {/* Search and filter */}
79      <div className="task-filters">
80        <input
81          type="text"
82          value={searchText}
83          onChange={(e) => setSearchText(e.target.value)}
84          placeholder="Search tasks..."
85        />
86        <label>
87          <input
88            type="checkbox"
89            checked={showCompleted}
90            onChange={() => toggleShowCompleted()}
91          />
92          Show completed tasks
93        </label>
94      </div>
95
96      {/* Task list */}
97      <ul className="task-list">
98        {filteredTasks.length === 0 ? (
99          <li className="empty-state">No tasks found</li>
100        ) : (
101          filteredTasks.map((task) => (
102            <li key={task.id} className={task.completed ? "completed" : ""}>
103              <input
104                type="checkbox"
105                checked={task.completed}
106                onChange={() => toggleTask(task.id)}
107              />
108              <span>{task.text}</span>
109              <button onClick={() => removeTask(task.id)}>Delete</button>
110            </li>
111          ))
112        )}
113      </ul>
114    </div>
115  );
116}
117

This example demonstrates how multiple hooks can work together to create a feature-rich application with persistent storage, debounced search, and toggle functionality.

Troubleshooting Tips

Hook Not Found

If you encounter a "Hook not found" error, try searching for similar hooks:

1npx usehooks-cli@latest search "keyword"
2

Dependency Conflicts

If you experience dependency conflicts, you can manually resolve them by editing your package.json or use the --clean-deps flag when removing hooks.

TypeScript Errors

Make sure your TypeScript configuration is compatible with the hooks. Most hooks require TypeScript 4.0 or higher and the appropriate DOM lib settings.

Conclusion

In this tutorial, you've learned how to use usehooks-cli to streamline your React development workflow. By leveraging this powerful tool, you can:

  • Quickly discover and add well-tested hooks to your projects
  • Maintain consistency across your codebase
  • Keep your hooks up-to-date with minimal effort
  • Focus on building features rather than writing boilerplate code

The next time you find yourself writing a custom hook from scratch, remember that usehooks-cli might already have a solution ready for you to use. Happy coding!