Building a Custom Hook Library for Reusable Logic

Creating a custom hook library allows you to encapsulate reusable logic and share it across different components in your React application. This approach promotes code reusability and keeps your components clean and focused on UI logic.

1. Setting Up the Project

  • Initialize the Project:
    npx create-react-app custom-hooks-library --template typescript
    cd custom-hooks-library

2. Creating Custom Hooks

We'll create a few custom hooks to demonstrate reusable logic: useFetch, useToggle, and useForm.

2.1. useFetch Hook

The useFetch hook fetches data from an API and handles loading and error states.

  • Create the Hook:
    // src/hooks/useFetch.ts
    import { useState, useEffect } from 'react'; const useFetch = (url: string) => { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchData = async () => { try { const response = await fetch(url); if (!response.ok) { throw new Error('Network response was not ok'); } const result = await response.json(); setData(result); } catch (err) { setError(err); } finally { setLoading(false); } }; fetchData(); }, [url]); return { data, loading, error }; }; export default useFetch;
2.2. useToggle Hook

The useToggle hook manages boolean states, such as toggling visibility.

  • Create the Hook:
    // src/hooks/useToggle.ts
    import { useState } from 'react'; const useToggle = (initialState: boolean = false) => { const [state, setState] = useState(initialState); const toggle = () => { setState(!state); }; return [state, toggle] as const; }; export default useToggle;
2.3. useForm Hook

The useForm hook handles form state and validation.

  • Create the Hook:
    // src/hooks/useForm.ts
    import { useState } from 'react'; const useForm = (initialValues: { [key: string]: any }) => { const [values, setValues] = useState(initialValues); const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { const { name, value } = e.target; setValues({ ...values, [name]: value, }); }; const resetForm = () => { setValues(initialValues); }; return { values, handleChange, resetForm }; }; export default useForm;

3. Using Custom Hooks in Components

Let's create a component that utilizes these custom hooks.

  • Create a Component:
    // src/components/CustomHookDemo.tsx
    import React from 'react'; import useFetch from '../hooks/useFetch'; import useToggle from '../hooks/useToggle'; import useForm from '../hooks/useForm'; const CustomHookDemo: React.FC = () => { const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/posts/1'); const [isToggled, toggle] = useToggle(); const { values, handleChange, resetForm } = useForm({ username: '', email: '' }); if (loading) return <p>Loading...</p>; if (error) return <p>Error: {error.message}</p>; return ( <div> <h1>Custom Hook Demo</h1> <div> <h2>Fetch Data</h2> <pre>{JSON.stringify(data, null, 2)}</pre> </div> <div> <h2>Toggle Visibility</h2> <button onClick={toggle}>{isToggled ? 'Hide' : 'Show'}</button> {isToggled && <p>Toggle content visible!</p>} </div> <div> <h2>Form Handling</h2> <form> <label> Username: <input type="text" name="username" value={values.username} onChange={handleChange} /> </label> <br /> <label> Email: <input type="email" name="email" value={values.email} onChange={handleChange} /> </label> <br /> <button type="button" onClick={resetForm}>Reset</button> </form> <pre>{JSON.stringify(values, null, 2)}</pre> </div> </div> ); }; export default CustomHookDemo;

4. Rendering the Component

  • Include the Component in Your App:
    // src/App.tsx
    import React from 'react'; import CustomHookDemo from './components/CustomHookDemo'; const App: React.FC = () => { return ( <div className="App"> <h1>Custom Hook Library Demo</h1> <CustomHookDemo /> </div> ); }; export default App;

5. Styling the Component

  • Add CSS for Better Presentation:
    /* src/App.css */
    .App { font-family: Arial, sans-serif; text-align: center; padding: 20px; } form { display: inline-block; text-align: left; } label { display: block; margin-bottom: 5px; } input { padding: 8px; margin-bottom: 10px; } button { padding: 10px 15px; background-color: #007bff; color: white; border: none; border-radius: 5px; cursor: pointer; } button:hover { background-color: #0056b3; } pre { text-align: left; }

By following these steps, you can build a custom hook library for reusable logic in React. This approach enhances code maintainability, promotes reusability, and keeps your components focused on their primary responsibilities.