01 Hook
React Hooks 是一种在 React 函数组件中添加状态管理和生命周期功能的方式。Hooks 于 React 16.8 引入,解决了之前只有类组件才能使用这些功能的限制。常用的 Hooks 包括 useState
、useEffect
、useContext
、useReducer
等。
常见的 React Hook 及其使用场景
-
useState
:用于在函数组件中声明状态变量。-
场景:需要存储组件内的动态数据,例如用户输入、计 数器等。
-
示例:
import React, { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
-
-
useEffect
:用于在函数组件中执行副作用操作,例如数据获取、订阅等。-
场景:替代生命周期函数(如
componentDidMount
、componentDidUpdate
、componentWillUnmount
)。 -
示例:
import React, { useState, useEffect } from "react";
function FetchData() {
const [data, setData] = useState(null);
useEffect(() => {
fetch("https://api.example.com/data")
.then((response) => response.json())
.then((data) => setData(data));
}, []); // 空数组使得副作用仅在初次渲染时执行
return <div>{data ? JSON.stringify(data) : "Loading..."}</div>;
}
-
-
useContext
:用于在组件树中传递数据,避免在每个层级手动传递 props。-
场景:在多层嵌套组件中共享状态,例如主题、语言等设置。
-
示例:
import React, { createContext, useContext } from "react";
const ThemeContext = createContext("light");
function ThemedComponent() {
const theme = useContext(ThemeContext);
return <div>Current theme: {theme}</div>;
}
function App() {
return (
<ThemeContext.Provider value="dark">
<ThemedComponent />
</ThemeContext.Provider>
);
}
-
-
useReducer
:用于复杂状态逻辑管理,类似于 Redux 的 reducer 概念。-
场景:当组件的状态更新逻辑复杂且涉及多个子状态时。
-
示例:
import React, { useReducer } from "react";
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();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: "increment" })}>
Increment
</button>
<button onClick={() => dispatch({ type: "decrement" })}>
Decrement
</button>
</div>
);
}
-
Hooks 的底层原理
React Hooks 的实现基于一组机制,主要包括闭包、依赖数组和单链表数据结构来实现 Hook 调用的顺序追踪:
-
单链表机制:React 在渲染函数组件时 会记录调用的每个 Hook。每次渲染时,它会保持 Hooks 的调用顺序一致性,便于在后续渲染中将状态和副作用绑定到正确的 Hook。
-
闭包:由于 Hooks 会在函数组件中捕获状态和函数作用域的变量,所以闭包让 React 能够将最新的状态和属性保存在作用域中,从而确保组件行为正确。
-
依赖数组:
useEffect
和useCallback
等 Hooks 的依赖数组用来控制副作用或函数的重新创建时机。React 使用依赖数组的变化来判断是否需要重新执行某些操作,避免不必要的性能开销。 -
调度机制:React 通过调度器(Scheduler)来管理 Hook 调用的顺序和状态更新的顺序,使得多次状态更新能够批处理完成。
-
虚拟 DOM 和 Fiber:Hooks 与 React 的 Fiber 架构协同工作,能够在虚拟 DOM 的 reconciliation 过程中跟踪每个组件的状态并高效更新。
Hooks 的优点
- 简洁代码:替代类组件,更简洁直观。
- 代码复用:通过自定义 Hook 抽离逻辑,代码更易复用。
- 组件逻辑集中:相比于类组件,将 UI 和逻辑更自然地整合在一起。
自定义 Hook 示例
以下是一个自定义 Hook 示例,实现计数逻辑的复用:
import { useState } from "react";
function useCounter(initialValue = 0) {
const [count, setCount] = useState(initialValue);
const increment = () => setCount((c) => c + 1);
const decrement = () => setCount((c) => c - 1);
return { count, increment, decrement };
}
// 使用自定义 Hook
function CounterComponent() {
const { count, increment, decrement } = useCounter(10);
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
}
这个自定义 Hook useCounter
可以在多个组件中复用计数逻辑,不必重复实现相同的逻辑。