什么是React Hooks?
React Hooks是让你在函数组件中使用React特性(如状态和生命周期方法)的函数。它们使代码更清晰、更简单。
为什么要引入Hooks?
React Hooks解决了类组件存在的几个问题:
- 类的复杂性:
在类组件中管理生命周期和状态通常容易出错。Hooks简化了这一点。
- 逻辑可重用性:
钩子使跨组件重用逻辑变得更容易,而不需要使用HOC或者 props。
- 提高代码可读性:
钩子简化了组件代码,使其更短,更容易理解。
- 增量采用:
钩子可以与类组件一起使用,允许逐步迁移。
React Hooks原理
React提供了几个钩子。让我们用例子来探索每一个。
useState
管理组件中的状态:
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0); // Initialize state
return (
<div>
<p>Current Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
export default Counter;
说明:
- useState将状态变量count初始化为0。
- setCount更新状态。
useEffect
处理副作用,如获取数据或更新DOM。
import React, { useState, useEffect } from 'react';
function Timer() {
const [time, setTime] = useState(0);
useEffect(() => {
const interval = setInterval(() => setTime(t => t + 1), 1000);
return () => clearInterval(interval); // Cleanup on unmount
}, []); // Run once on mount
return <p>Elapsed Time: {time}s</p>;
}
export default Timer;
说明:
- 组件装载时,执行一次
- 页面卸载时清除间隔
useContext
访问上下文
import React, { useContext, createContext } from 'react';
const ThemeContext = createContext('light');
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button style={{ background: theme === 'dark' ? '#333' : '#fff' }}>I am {theme} themed</button>;
}
function App() {
return (
<ThemeContext.Provider value="dark">
<ThemedButton />
</ThemeContext.Provider>
);
}
export default App;
说明:
- useContext从最近的ThemeContext.Provider获取值
useReducer
管理复杂的状态逻辑:
import React, { useReducer } from 'react';
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('Unknown action type');
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
<button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
</div>
);
}
export default Counter;
说明:
- useReducer管理复杂的状态判断。
useRef
持久化值或引用DOM节点。
import React, { useRef } from 'react';
function FocusInput() {
const inputRef = useRef();
const focus = () => inputRef.current.focus();
return (
<div>
<input ref={inputRef} placeholder="Click button to focus" />
<button onClick={focus}>Focus Input</button>
</div>
);
}
export default FocusInput;
说明:
- ref提供对DOM元素的引用。
useMemo
惰性计算:
import React, { useMemo } from 'react';
function Factorial({ number }) {
const factorial = useMemo(() => {
const calculateFactorial = n => (n <= 1 ? 1 : n * calculateFactorial(n - 1));
return calculateFactorial(number);
}, [number]);
return <p>Factorial of {number}: {factorial}</p>;
}
export default Factorial;
说明:
- useMemo避免重新计算阶乘,除非数字发生变化。
useCallback
import React, { useState, useCallback } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const increment = useCallback(() => setCount(prev => prev + 1), []);
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
export default Counter;
说明:
- 防止在重新渲染时不必要地重新创建。
useLayoutEffect
import React, { useState, useLayoutEffect, useRef } from 'react';
function Box() {
const boxRef = useRef();
const [color, setColor] = useState('blue');
useLayoutEffect(() => {
console.log('Box dimensions:', boxRef.current.getBoundingClientRect());
}, [color]);
return (
<div>
<div ref={boxRef} style={{ width: 100, height: 100, background: color }}></div>
<button onClick={() => setColor(color === 'blue' ? 'red' : 'blue')}>Toggle Color</button>
</div>
);
}
export default Box;
说明:
- useLayoutEffect确保在浏览器绘制之前计算DOM。