Frontend Development 26 min read

React Custom Hooks: Definition, Usage, Design Principles, and Applications

This article explains what React custom hooks are, how to define and use them, outlines design principles, discusses performance optimizations, and provides practical examples such as form validation and component communication, all aimed at improving code reuse and maintainability.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
React Custom Hooks: Definition, Usage, Design Principles, and Applications

1 Overview of React Custom Hooks

1.1 Definition and Advantages of Hooks

Hooks, introduced in React 16.8, are special functions that let you "hook into" state, lifecycle, and other React features inside functional components, eliminating the need for class‑based this.state and this.props.

Common built‑in hooks include useState , useEffect , useContext , and many others such as useReducer , useCallback , useMemo , useRef .

useState : adds and manages state in a functional component.

useEffect : handles side effects like data subscriptions, network requests, or event listeners.

useContext : accesses React context without using static contextType or this.context.

Advantages of hooks are more concise code, better logic reuse, flexible component design, and easier testing.

1.2 Custom Hooks

Custom hooks are reusable functions that start with the use prefix, allowing you to extract component logic for sharing across multiple components.

import { useState } from "react";

function useForm(initialState) {
  const [values, setValues] = useState(initialState);
  const handleChange = (event) => {
    setValues({ ...values, [event.target.name]: event.target.value });
  };
  const resetForm = () => {
    setValues(initialState);
  };
  return [values, handleChange, resetForm];
}
export default useForm;

Usage in a component:

import React from "react";
import useForm from "./useForm";

function MyForm() {
  const [values, handleChange, resetForm] = useForm({ name: "", email: "" });

  const handleSubmit = (event) => {
    event.preventDefault();
    // handle submit logic
  };

  return (
Submit
Reset
);
}
export default MyForm;

1.3 Design Principles for Custom Hooks

Single Responsibility Principle – focus on one problem.

Clear Function Signature – descriptive parameters and return values.

Naming Convention – start with use and use camelCase.

Configurability – provide options to adapt to different scenarios.

Testability – make the hook easy to unit‑test.

Documentation and Comments – explain purpose, parameters, and usage.

Follow Hooks Rules – only call other hooks at the top level.

Good Naming and Abstraction – keep names meaningful and abstractions clear.

2 Using React Custom Hooks

2.1 Naming Conventions and Guidelines

Names must start with use , use camelCase, accurately describe functionality, optionally end parameter names with Options , return an array or object, and be declared with const . Store hook files under a src/hooks directory (e.g., src/hooks/useFetchData.js ).

2.2 Defining and Using Custom Hooks

Define a hook as a regular function that returns state and helper functions.

import { useState, useEffect } from 'react';

function useCustomHook() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `Count: ${count}`;
  }, [count]);

  const increment = () => setCount(prev => prev + 1);
  return [count, increment];
}
export default useCustomHook;

Consume the hook in a component:

import React from 'react';
import useCustomHook from './useCustomHook';

function App() {
  const [count, increment] = useCustomHook();
  return (
Count: {count}
Increment
);
}
export default App;

2.3 Common Application Scenarios

State management across components.

Side‑effect handling (data fetching, timers, subscriptions).

Data fetching and processing.

Form handling and validation.

Timers and animation effects.

Browser API access (geolocation, local storage, history).

Encapsulation of complex business logic.

3 Optimization Effects of React Custom Hooks

3.1 Component Performance Optimization

3.1.1 Avoid Unnecessary Renders

Use shouldComponentUpdate , PureComponent , or React.memo to skip renders when props/state have not changed. Pass only needed props, avoid creating new objects/functions inside render, and limit frequent setState calls.

3.1.2 Reduce Duplicate Code

Extract repeated logic into functions or components, use higher‑order components, render‑props, abstract common UI components, or custom hooks to keep code DRY.

3.2 Logic Reuse and Abstraction

3.2.1 Shared State Logic

Lift state to a common parent, use React Context, Redux or other state libraries, useReducer , or third‑party tools like Zustand or Recoil.

3.2.2 Encapsulating Complex Logic

Custom hooks, higher‑order components, render‑props, abstract components, or utility functions can encapsulate complex behavior for reuse.

4 Practical Examples

4.1 Example 1: Form Validation Hook

import { useState } from 'react';

// Custom form validation hook
const useFormValidator = () => {
  const [values, setValues] = useState({});
  const [errors, setErrors] = useState({});

  const handleChange = (e) => {
    const { name, value } = e.target;
    setValues(prev => ({ ...prev, [name]: value }));
  };

  const validate = (vals) => {
    const errs = {};
    if (!vals.username) errs.username = 'Please enter a username';
    if (!vals.email) errs.email = 'Please enter an email';
    else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(vals.email))
      errs.email = 'Invalid email address';
    return errs;
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    const validationErrors = validate(values);
    setErrors(validationErrors);
    if (Object.keys(validationErrors).length === 0) {
      // submit form
    }
  };

  return { values, errors, handleChange, handleSubmit };
};

function LoginForm() {
  const { values, errors, handleChange, handleSubmit } = useFormValidator();
  return (
{errors.username &&
{errors.username}
}
{errors.email &&
{errors.email}
}
Submit
);
}
export default LoginForm;

4.2 Example 2: Component Communication Hook

import { useState, useEffect } from 'react';

// Custom communication hook
const useCommunication = () => {
  const [message, setMessage] = useState('');
  const sendMessage = (msg) => setMessage(msg);
  return { message, sendMessage };
};

function MessageReceiver() {
  const { message } = useCommunication();
  return
{message}
;
}

function MessageSender() {
  const { sendMessage } = useCommunication();
  useEffect(() => {
    sendMessage('Hello, MessageReceiver!');
  }, [sendMessage]);
  return
Send Message
;
}
export { MessageReceiver, MessageSender };

5 Conclusion

Custom hooks provide a powerful way to encapsulate complex logic and enable component communication, improving maintainability, reusability, testability, and performance in React applications.

Performance OptimizationJavaScriptFrontend Developmentstate managementreactComponent ReuseCustom Hooks
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.