React 词条目录
前端Wiki/React/深入/性能优化与自定义 Hook

自定义 Hook

自定义 Hook = 把组件间可复用的“状态逻辑”抽成函数:函数名以 use 开头、内部调用其他 Hooks、返回需要的数据与方法。它复用的是逻辑而非界面——组件还是各自渲染,状态互不共享。

例如“展开/折叠”逻辑要在三处用:写成 useToggle() 后,每个组件一行 const [open, toggle] = useToggle() 就能用。常见轮子还有 useLocalStorage(状态同步进 localStorage)、useFetch(请求 + loading + error)、useWindowSize(窗口尺寸)。

  • 自定义 Hook = 以 use 开头、内部用其他 Hooks 的普通函数
  • 复用的是逻辑不是状态:各组件各一份数据
  • 抽离时机:同一段状态逻辑出现第二次时
HTML
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>自定义 Hook</title>
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState, useEffect } = React;

// 自定义 Hook:开关逻辑,多个组件可各自复用
function useToggle(initial = false) {
  const [open, setOpen] = useState(initial);
  const toggle = () => setOpen(o => !o);
  return [open, toggle];
}

// 自定义 Hook:状态与 localStorage 同步
function useLocalStorage(key, initial) {
  const [value, setValue] = useState(() => {
    try { return JSON.parse(localStorage.getItem(key)) ?? initial; }
    catch (e) { return initial; }
  });
  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);
  return [value, setValue];
}

function Panel({ title }) {
  const [open, toggle] = useToggle(false);    // 复用开关逻辑
  return (
    <div style={{ padding: 8 }}>
      <button onClick={toggle}>{open ? '折叠' : '展开'} {title}</button>
      {open && <p>{title} 的内容:两个面板各自独立。</p>}
    </div>
  );
}

function App() {
  const [name, setName] = useLocalStorage('demo-name', '');
  return (
    <div style={{ padding: 16 }}>
      <Panel title="面板 A" />
      <Panel title="面板 B" />
      <hr />
      <input value={name} onChange={e => setName(e.target.value)} placeholder="刷新页面仍在" />
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
</script>
</body>
</html>
本节要点自定义 Hook 把状态逻辑抽成 use 函数:复用逻辑不共享状态,是 React 复用的正道。