𝑻𝒆𝒏𝑪𝒍𝒂𝒘正在头脑风暴···
𝑻𝒆𝒏𝑲𝒊𝑺𝒆𝒀𝒂の𝑨𝒈𝒆𝒏𝒕助手
𝑻𝒆𝒏-𝒇𝒍𝒂𝒔𝒉

React Hooks 深入理解

React Hooks 是 React 16.8 引入的新特性,它让你可以在函数组件中使用状态和其他 React 特性。

为什么需要 Hooks?

Hooks 解决了类组件的几个问题:

  1. 组件逻辑复用困难(HOC、Render Props 复杂)
  2. 类组件难以理解和维护
  3. 组件间逻辑共享代码复杂

常用 Hooks

useState

function Counter() {
const [count, setCount] = useState(0);

return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}

useEffect

useEffect(() => {
// 副作用逻辑
document.title = `You clicked ${count} times`;

// 清理函数
return () => {
document.title = 'React App';
};
}, [count]); // 依赖数组

useContext

const ThemeContext = React.createContext('light');

function ThemedButton() {
const theme = useContext(ThemeContext);
return <button className={theme}>I am styled by theme context!</button>;
}

useMemo

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

useCallback

const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);

自定义 Hooks

// 使用自定义 Hooks
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);

useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);

return width;
}

// 使用示例
function App() {
const width = useWindowWidth();
return <p>Window width: {width}</p>;
}

规则和最佳实践

  1. 只在顶层调用 Hooks:不要在循环、条件语句或嵌套函数中调用 Hooks
  2. 只在 React 函数中调用 Hooks:在 React 函数组件或自定义 Hook 中调用
  3. 命名规范:以 use 开头,如 useMyCustomHook

性能优化

// 避免不必要的重新渲染
const MemoizedComponent = React.memo(MyComponent);

// 优化大列表
function BigList({ items }) {
const renderRow = useCallback(
(index) => <Row item={items[index]} />,
[items]
);

return <List itemCount={items.length} renderRow={renderRow} />;
}

Hooks 设计模式

条件 Hook

function useFormInput(initialValue) {
const [value, setValue] = useState(initialValue);

return {
value,
onChange: (e) => setValue(e.target.value),
reset: () => setValue(initialValue)
};
}

组合模式

function useDataFetching(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
const data = await response.json();
setData(data);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};

fetchData();
}, [url]);

return { data, loading, error };
}

常见问题解决

避免闭包陷阱

// 错误示例
function Counter() {
const [count, setCount] = useState(0);

const increment = () => {
setCount(count + 1);
};

return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>+</button>
</div>
);
}

// 正确示例
function Counter() {
const [count, setCount] = useState(0);

const increment = () => {
setCount(c => c + 1); // 使用函数形式
};

return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>+</button>
</div>
);
}

[!tip]
使用 useCallback 包装事件处理函数,避免不必要的重新渲染。

总结

React Hooks 提供了一种更简洁、更直观的方式来编写 React 组件。掌握 Hooks 可以让你写出更好的 React 代码。

参考资料