componentDidUpdate
的复杂逻辑shouldComponentUpdate
优化成本高特性 | 类组件 | Hooks |
---|---|---|
代码量 | 平均多 40% | 更简洁 |
逻辑复用 | HOC/Render Props | 自定义 Hooks |
学习曲线 | 生命周期复杂 | 函数式思维 |
TS 支持 | 类型注解繁琐 | 完美支持 |
打包体积 | 较大 | 减少 30% |
function Counter() {
const [count, setCount] = useState(() => {
// 惰性初始化
const initial = Number(localStorage.getItem('count')) || 0;
return initial;
});
// 批量更新示例
const handleClick = () => {
setCount(prev => prev + 1);
setCount(prev => prev + 1);
};
return ;
}
最佳实践:
function DataFetcher({ id }) {
const [data, setData] = useState(null);
useEffect(() => {
let isMounted = true;
const fetchData = async () => {
const result = await api.get(`/data/${id}`);
if(isMounted) setData(result);
};
fetchData();
return () => {
isMounted = false;
// 清理异步操作
};
}, [id]); // 依赖项精准控制
return {JSON.stringify(data)};
}
依赖项处理原则:
const ThemeContext = createContext('light');
function App() {
return (
);
}
function Toolbar() {
const theme = useContext(ThemeContext);
return ;
}
性能优化:
const todoReducer = (state, action) => {
switch (action.type) {
case 'ADD':
return [...state, action.payload];
case 'TOGGLE':
return state.map(todo =>
todo.id === action.id ? {...todo, done: !todo.done} : todo
);
default:
return state;
}
};
function TodoList() {
const [todos, dispatch] = useReducer(todoReducer, []);
return (
<>
{/* 列表渲染 */}
>
);
}
function Stopwatch() {
const [time, setTime] = useState(0);
const intervalRef = useRef();
const start = () => {
intervalRef.current = setInterval(() => {
setTime(prev => prev + 1);
}, 1000);
};
const stop = () => {
clearInterval(intervalRef.current);
};
return (
{time}s
);
}
function useWindowSize() {
const [size, setSize] = useState({
width: window.innerWidth,
height: window.innerHeight
});
useEffect(() => {
const handler = () => {
setSize({
width: window.innerWidth,
height: window.innerHeight
});
};
window.addEventListener('resize', handler);
return () => window.removeEventListener('resize', handler);
}, []);
return size;
}
// 使用示例
function ResponsiveComponent() {
const { width } = useWindowSize();
return 当前宽度: {width}px;
}
const ExpensiveComponent = React.memo(({ list }) => {
// 复杂计算
const processedList = useMemo(() =>
list.map(item => heavyCompute(item))
, [list]);
return (
{processedList.map(item => (
- {item.text}
))}
);
});
function UserProfile({ userId }) {
const fetchUser = useCallback(async () => {
return await getUser(userId);
}, [userId]);
useEffect(() => {
fetchUser().then(/* 更新状态 */);
}, [fetchUser]);
}
function ProfiledComponent() {
useWhyDidYouUpdate('MyComponent', { prop1, prop2 });
return /* ... */;
}
// 自定义调试 Hook
function useWhyDidYouUpdate(name, props) {
const previousProps = useRef();
useEffect(() => {
if (previousProps.current) {
const changes = {};
Object.keys(props).forEach(key => {
if (previousProps.current[key] !== props[key]) {
changes[key] = {
from: previousProps.current[key],
to: props[key]
};
}
});
if (Object.keys(changes).length) {
console.log('[why-did-you-update]', name, changes);
}
}
previousProps.current = props;
});
}
目录结构:
src/
hooks/
useAuth.js
useAPI.js
useForm.js
命名规则:
use
前缀use[Feature]State
use[Utility]
测试方案:
// 使用 React Testing Library
test('should update count', () => {
const { result } = renderHook(() => useCounter());
act(() => result.current.increment());
expect(result.current.count).toBe(1);
});
场景 | 推荐方案 | 说明 |
---|---|---|
局部状态 | useState | 组件内部简单状态 |
复杂状态 | useReducer | 多操作、依赖之前状态 |
全局共享 | Context + useReducer | 中小型应用 |
大型应用 | Redux Toolkit | 需要时间旅行等特性 |
闭包陷阱:
function Timer() {
const [count, setCount] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
// 错误:总是得到初始值
setCount(count + 1);
}, 1000);
return () => clearInterval(timer);
}, []); // 缺少依赖
// 正确写法
useEffect(() => {
const timer = setInterval(() => {
setCount(prev => prev + 1);
}, 1000);
return () => clearInterval(timer);
}, []);
}
无限循环:
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
// 错误:未处理 userId 未变化的情况
fetchUser(userId).then(setUser);
}, [userId, user]); // 错误依赖
// 正确写法
useEffect(() => {
if (!userId) return;
let isMounted = true;
fetchUser(userId).then(data => {
if(isMounted) setUser(data);
});
return () => { isMounted = false };
}, [userId]);
}
const handleSubmit = useEvent(() => {
// 总能访问最新 props/state
});
function SearchResults({ query }) {
const results = useDeferredValue(fetchResults(query));
return (
}>
);
}
// Server Component
export default function ProductPage({ params }) {
const product = await db.getProduct(params.id);
return (
<>
}>
{/* Client Component */}
>
);
}
通过本文的系统学习,开发者可以全面掌握 React Hooks 的核心概念与实战技巧。建议在项目中遵循 “渐进式采用” 原则,从简单组件开始实践,逐步应用到复杂场景。记住:Hooks 不是对类组件的简单替代,而是提供了更符合现代 React 开发理念的新范式。保持对官方更新的关注,持续优化代码质量,才能充分发挥 Hooks 的强大威力。