Mastering React Hooks: Practical Guide, Patterns, and Performance Tips

This article explains React Hooks introduced in version 16.8, their backward‑compatible design, how they replace class components, and provides detailed guidance on using useState, useEffect, custom hooks, useReducer, useRef, useMemo, useCallback, and related linting rules with performance‑focused examples.

MaoDou Frontend Team
MaoDou Frontend Team
MaoDou Frontend Team
Mastering React Hooks: Practical Guide, Patterns, and Performance Tips

React Hooks

Notes

Available since React 16.8

Fully backward compatible, optional, and ready to use immediately

Class components are not removed; Hooks are the future‑preferred API

All class‑based lifecycle methods have Hook equivalents (except rarely used error boundaries)

Better TypeScript support and performance because class overhead is avoided

Logic reuse is achieved without higher‑order components or render props.

Basic Example

function Example() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `Clicked ${count} times`;
  });
  return (
    <div>
      <p>Clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click</button>
    </div>
  );
}

Hook Rules

Hooks must be called at the top level of a React function component or a custom Hook.

Never call Hooks inside loops, conditions, or nested functions.

The order of Hook calls must be the same on every render.

State Hook – useState

const [state, setState] = useState(initialState);

Multiple independent state variables can be declared by calling useState several times. The initial state can be a primitive, object, or lazily computed value.

// Lazy initialization
const [state, setState] = useState(() => {
  const initial = expensiveComputation(props);
  return initial;
});

Effect Hook – useEffect

useEffect(() => {
  // side‑effects such as data fetching, subscriptions, DOM updates
  return () => {
    // optional cleanup
  };
}, [dep1, dep2]);

useEffect replaces componentDidMount, componentDidUpdate, and componentWillUnmount. The second argument controls when the effect runs; an empty array runs only on mount/unmount.

Custom Hook Example

function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}

Reducer Hook – useReducer

const initialState = { count: 0 };
function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}
function Counter({ initialState }) {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
    </>
  );
}

Context Hook – useContext

Provides a way to share values like a dispatch function across the component tree without prop drilling.

const TodosDispatch = React.createContext(null);
function TodosApp() {
  const [todos, dispatch] = useReducer(todosReducer);
  return (
    <TodosDispatch.Provider value={dispatch}>
      <DeepTree todos={todos} />
    </TodosDispatch.Provider>
  );
}
function DeepChild() {
  const dispatch = useContext(TodosDispatch);
  return <button onClick={() => dispatch({ type: 'add', text: 'hello' })}>Add todo</button>;
}

Reference Hook – useRef

function Timer() {
  const intervalRef = useRef();
  useEffect(() => {
    const id = setInterval(() => { /* … */ }, 1000);
    intervalRef.current = id;
    return () => clearInterval(intervalRef.current);
  });
  // intervalRef can be read or cleared elsewhere
}

Memoization Hooks – useMemo & useCallback

const memoizedValue = useMemo(() => computeExpensive(a, b), [a, b]);
const stableCallback = useCallback(() => {
  // function body
}, [dep]);

Both hooks help avoid unnecessary recomputation or re‑creation of functions between renders.

Imperative Handle – useImperativeHandle

function FancyInput(props, ref) {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => inputRef.current.focus()
  }));
  return <input ref={inputRef} />;
}
FancyInput = forwardRef(FancyInput);

Async Data Fetching Example

function SearchResults() {
  const [data, setData] = useState({ hits: [] });
  const [query, setQuery] = useState('react');
  useEffect(() => {
    let ignore = false;
    async function fetchData() {
      const result = await axios('https://hn.algolia.com/api/v1/search?query=' + query);
      if (!ignore) setData(result.data);
    }
    fetchData();
    return () => { ignore = true; };
  }, [query]);
  return (
    <>
      <input value={query} onChange={e => setQuery(e.target.value)} />
      <ul>{data.hits.map(item => <li key={item.objectID}><a href={item.url}>{item.title}</a></li>)}</ul>
    </>
  );
}

Linting – eslint-plugin-react-hooks

The exhaustive-deps rule warns when Hook dependency arrays are incomplete, helping prevent stale closures and bugs.

Performance Tips

Avoid unnecessary re‑renders by memoizing components with React.memo and using useMemo for expensive calculations.

Prefer functional state updates when the new state depends on the previous one.

Use lazy initialization for heavy state setup.

Overall, Hooks enable a more functional, composable, and performant way to write React components while keeping the codebase easier to understand and test.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaScriptReacthooksuseEffectuseState
MaoDou Frontend Team
Written by

MaoDou Frontend Team

Open-source, innovative, collaborative, win‑win – sharing frontend tech and shaping its future.

0 followers
Reader feedback

How this landed with the community

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.