Frontend Development 18 min read

Understanding React Hooks: Principles, Implementation, and Usage

This article explains why React introduced Hooks, how they solve state‑reuse and component‑complexity problems, details the internal fiber architecture behind useState, useReducer, useEffect, useLayoutEffect, useCallback and useMemo, and provides practical code examples for each.

Beike Product & Technology
Beike Product & Technology
Beike Product & Technology
Understanding React Hooks: Principles, Implementation, and Usage

React 16.8 added Hooks to allow state and other React features without writing class components. The article begins by describing the pain points Hooks address, such as difficulty reusing state logic across components and the complexity of class‑based lifecycle methods.

It demonstrates a custom Hook for scroll‑position tracking, showing how to replace repetitive event‑listener code with a reusable function. The example code is provided below:

const getPosition = () => {
  left: document.body.scrollLeft,
  top: document.body.scrollTop
}

const BackToTop = (props) => {
  const [position, setPosition] = useState(getPosition())
  useEffect(() => {
    const handler = () => setPosition(getPosition())
    document.addEventListener("scroll", handler)
    return () => { document.removeEventListener("scroll", handler) }
  }, [])
  return position.top > 600 ? '返回顶部' : ''
}

A custom Hook usePosition abstracts this logic, reducing nesting and improving readability compared with render‑props or higher‑order components.

const usePosition = () => {
  const [position, setPosition] = useState(getPosition())
  useEffect(() => {
    const handler = () => setPosition(getPosition())
    document.addEventListener("scroll", handler)
    return () => { document.removeEventListener("scroll", handler) }
  }, [])
  return position
}

The article then analyzes the internal workings of several core Hooks. For useState , it shows the fiber data structure that stores memoizedState , baseState , and an update queue. A simple counter example illustrates initial render, state updates via setCount , and subsequent renders.

import React, { useState } from 'react'
function App() {
  const [count, setCount] = useState(0)
  return (
{count}
{ setCount(1); setCount(state => state + 2); setCount(state => state + 3) }}>加
)
}
export default App

It explains how setCount enqueues updates in a circular linked list, why the queue is circular, and how the render phase computes the new state during the commit phase.

The differences between useReducer and useState are covered, with an example showing a reducer that handles increment and decrement actions.

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() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
dispatch({type: 'decrement'})}>-
dispatch({type: 'increment'})}>+
);
}

For side‑effects, the article contrasts useEffect and useLayoutEffect , mapping them to class lifecycle methods and describing their execution order across the render, before‑mutation, mutation, and layout phases. It includes diagrams of the render‑with‑hooks flow and the commit pipeline.

import React, { useState, useEffect } from 'react'
function App() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    console.log('useEffect:', count);
    return () => console.log('useEffect destroy:', count);
  }, [count]);
  return (
{count}
setCount(count + 1)}>加1
);
}
export default App;

Performance‑optimising Hooks are then discussed. useCallback memoises a function reference, preventing unnecessary child re‑renders, while useMemo memoises the result of an expensive computation. Example code shows both in action.

import React, { useState, useCallback } from 'react'
function Parent() {
  const [count, setCount] = useState(1);
  const callback = useCallback(() => count, [count]);
  return
;
}
function Child({ callback }) {
  const [c, setC] = useState(() => callback());
  useEffect(() => { setC(callback()); }, [callback]);
  return
{c}
;
}
import React, { useState, useMemo } from 'react'
function ExpensiveComponent() {
  const [count, setCount] = useState(1);
  const expensive = useMemo(() => {
    let sum = 0;
    for (let i = 0; i < count * 100; i++) sum += i;
    return sum;
  }, [count]);
  return
{expensive}
;
}

Finally, the article summarises best practices: use custom Hooks for reusable logic, prefer useCallback when passing functions to children, use useMemo to cache heavy calculations, and apply useEffect or useLayoutEffect according to timing requirements.

frontendjavascriptReactHooksuseEffectuseState
Beike Product & Technology
Written by

Beike Product & Technology

As Beike's official product and technology account, we are committed to building a platform for sharing Beike's product and technology insights, targeting internet/O2O developers and product professionals. We share high-quality original articles, tech salon events, and recruitment information weekly. Welcome to follow us.

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.