Why React Hooks

目录 🔗︎

  1. React Hooks 的背景
  2. React Hooks 的使用
  3. 性能优化
  4. 总结

React Hooks 的背景 🔗︎

在 React 的早期版本中,我们使用 createClass 创建组件,随后在 React v0.13.0 中引入了 React.Component。然而,这种方式存在一些问题:

  1. 构造函数中的限制:在 constructor 中必须调用 super 方法,并将 props 传递给它。
  2. 手动绑定 this:需要手动绑定类方法中的 this

虽然可以通过 Class Fields箭头函数 来避免这些问题,但仍然会面临代码重复的问题。例如:

为了解决这些问题,开发者通常会使用 高阶组件(HOC)Render Props 模式来复用逻辑。然而,这些方法容易导致“包装地狱”(Wrapper Hell),并且代码可读性较差。

因此,React 团队推出了 React Hooks,旨在解决这些问题并提供更简洁、更灵活的开发方式。

React Hooks 的使用 🔗︎

useState 🔗︎

useState 是 React Hooks 中最基础的一个 Hook。它的作用是管理组件的状态。

  • 功能:接受初始状态(值或函数),返回一个数组,第一个元素是当前状态,第二个元素是更新状态的函数(如 setRepos)。
  • setState 的区别
    • setState 管理的是整个组件的状态对象,而 useState 只管理单个状态。
    • useState 的更新函数会完全替换状态,而 setState 会合并状态对象。

示例代码:

const [repos, setRepos] = useState([]);

useEffect 🔗︎

在传统的类组件中,生命周期方法用于同步副作用(如数据获取、订阅等)。在 React Hooks 中,useEffect 承担了这一职责。

  • 功能useEffect 在组件渲染后执行,类似于 componentDidMountcomponentDidUpdate
  • 触发时机
    • 如果未传递第二个参数,则会在每次重新渲染后执行。
    • 如果传递空数组 [],则只会在初始渲染时执行。
    • 如果传递依赖项数组,则仅在依赖项变化时执行。

为了避免无限循环,建议合理设置依赖项数组。此外,useEffect 提供了清理机制,用于处理如事件监听器或 WebSocket 等资源释放。

示例代码:

useEffect(() => {
  const handler = () => console.log('Window resized');
  window.addEventListener('resize', handler);
  return () => window.removeEventListener('resize', handler);
}, []);

自定义 Hooks 🔗︎

React 不仅是一个 UI 组件库,还需要处理大量的非视觉逻辑。为了复用逻辑,React 提供了 自定义 Hooks

  • 优势:避免 HOC 和 Render Props 的“包装地狱”,代码更易理解。
  • 命名规则:自定义 Hook 必须以 use 开头。

示例代码:

function useTooltip() {
  const [visible, setVisible] = useState(false);
  return { visible, show: () => setVisible(true), hide: () => setVisible(false) };
}

// 使用自定义 Hook
const tooltip = useTooltip();

useReducer 🔗︎

useReducer 是一种基于 Reducer 模式 的状态管理方式,适合处理复杂的状态逻辑。

  • 功能:通过 dispatch 触发状态更新,类似于 Redux 的工作方式。
  • 适用场景:当组件中有多个相互关联的状态时,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();
  }
}

const [state, dispatch] = useReducer(reducer, initialState);

useRef 🔗︎

useRef 用于在组件的多次渲染之间持久化某个值,或者访问 DOM 节点。

  • 功能
    • 持久化值:通过 ref.current 访问和修改值。
    • 访问 DOM:通过 ref 获取 DOM 节点。

示例代码:

const inputRef = useRef(null);

useEffect(() => {
  inputRef.current.focus();
}, []);

return <input ref={inputRef} />;

useContext 🔗︎

useContext 提供了一种跨组件共享数据的方式,避免了逐层传递 props 的繁琐。

示例代码:

const ThemeContext = createContext();

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Child />
    </ThemeContext.Provider>
  );
}

function Child() {
  const theme = useContext(ThemeContext);
  return <div>{theme}</div>;
}

性能优化 🔗︎

React.memo 🔗︎

React.memo 是一个高阶组件,用于跳过不必要的重新渲染。

示例代码:

const MemoizedComponent = React.memo(MyComponent);

useCallback 🔗︎

useCallback 用于缓存回调函数,避免在父组件重新渲染时生成新的函数实例。

示例代码:

const handleClick = useCallback(() => {
  console.log('Clicked');
}, []);

useMemo 🔗︎

useMemo 用于缓存计算结果,避免不必要的重新计算。

示例代码:

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

当发布很酷的东西时,请第一时间通知我

订阅电子邮件,以获得我的最新文章。我不会向您发送垃圾邮件。随时取消订阅。