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
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:
- Detect your project structure (Next.js, Vite, CRA, etc.)
- Suggest optimal locations for your hooks directory
- 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:
- Download the hook from the registry
- Add it to your hooks directory
- Install any required dependencies
- 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:
- Compare your installed hooks with the latest versions
- Create backups of your current hooks
- Apply updates where available
- 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:
- First, add the hooks we'll need:
1npx usehooks-cli@latest add use-local-storage use-boolean use-debounce
2
- 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!