DevPrep
  • Interview Prep
  • Projects
  • Resources
  • Pricing
  • About Us
Submit Question
DevPrep
  • Pricing
  • About Us
Submit Question
  1. Home
  2. Articles
  3. Frontend Engineering
  4. React Custom Hooks: Patterns and Anti-Patterns
XLinkedInReddit
MediumFrontend Engineering

React Custom Hooks: Patterns and Anti-Patterns

D
DevPrep Team
February 10, 2026·2 min read·0
Table of Contents
  • Rules of Hooks
  • Essential Patterns
  • useLocalStorage
  • useFetch
  • useMediaQuery
  • Anti-Patterns
  • 1. Too Many Responsibilities
  • 2. Unnecessary Hooks
  • 3. Missing Cleanup

Custom hooks are React's composition model. They replace HOCs and render props with something far more elegant. Here's how to write them properly.

Rules of Hooks

  1. Only call hooks at the top level (not in loops, conditions, or nested functions)
  2. Only call hooks from React functions (components or other hooks)
  3. Custom hooks must start with "use"

Essential Patterns

useLocalStorage

function useLocalStorage(key, initialValue) {
  const [value, setValue] = useState(() => {
    try {
      const item = localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch { return initialValue; }
  });

  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  return [value, setValue];
}

const [theme, setTheme] = useLocalStorage("theme", "dark");

useFetch

function useFetch(url) {
  const [state, setState] = useState({ data: null, loading: true, error: null });

  useEffect(() => {
    const controller = new AbortController();
    setState(s => ({ ...s, loading: true }));

    fetch(url, { signal: controller.signal })
      .then(res => res.json())
      .then(data => setState({ data, loading: false, error: null }))
      .catch(error => {
        if (error.name !== "AbortError") {
          setState({ data: null, loading: false, error });
        }
      });

    return () => controller.abort();
  }, [url]);

  return state;
}

useMediaQuery

function useMediaQuery(query) {
  const [matches, setMatches] = useState(
    () => window.matchMedia(query).matches
  );

  useEffect(() => {
    const mql = window.matchMedia(query);
    const handler = (e) => setMatches(e.matches);
    mql.addEventListener("change", handler);
    return () => mql.removeEventListener("change", handler);
  }, [query]);

  return matches;
}

const isMobile = useMediaQuery("(max-width: 768px)");

Anti-Patterns

1. Too Many Responsibilities

// Bad: does too much
function useUser() {
  const [user, setUser] = useState(null);
  const [posts, setPosts] = useState([]);
  const [notifications, setNotifications] = useState([]);
  // ... 200 lines of mixed concerns
}

// Good: single responsibility
function useUser() { /* just user data */ }
function useUserPosts(userId) { /* just posts */ }
function useNotifications() { /* just notifications */ }

2. Unnecessary Hooks

// Bad: this doesn't need to be a hook
function useFormatDate(date) {
  return new Date(date).toLocaleDateString();
}

// Good: just a utility function
function formatDate(date) {
  return new Date(date).toLocaleDateString();
}

3. Missing Cleanup

// Bad: memory leak
useEffect(() => {
  const interval = setInterval(fetchData, 5000);
  // Missing cleanup!
}, []);

// Good
useEffect(() => {
  const interval = setInterval(fetchData, 5000);
  return () => clearInterval(interval);
}, []);

Related Articles

MediumFrontend Engineering

System Design #12: Design a Multi-Step Form Wizard

7 min read
MediumFrontend Engineering

Mastering Senior-Level JavaScript Interview Concepts

2 min read
MediumFrontend Engineering

System Design #9: Design a Collaborative Text Editor

9 min read

Comments (0)

Sign in to leave a comment.

No comments yet. Be the first to comment.

Table of Contents

  • Rules of Hooks
  • Essential Patterns
  • useLocalStorage
  • useFetch
  • useMediaQuery
  • Anti-Patterns
  • 1. Too Many Responsibilities
  • 2. Unnecessary Hooks
  • 3. Missing Cleanup

Series

View all Frontend Engineering articles →

Practice

  • JavaScript
  • DSA
  • Machine Coding
  • System Design

Resources

  • Learning Tracks
  • Articles
  • Roadmaps
  • Compare Concepts
  • Glossary
  • Developer Tools
  • All Questions

Company

  • About
  • Pricing

Legal

  • Privacy Policy
  • Terms of Service
DevPrep

© 2026 DevPrep. All rights reserved.