React Common Hooks
除了 useState
,React 还提供了许多其他的 Hooks 用于管理组件的状态和生命周期。以下是一些常见的 Hooks,以及它们的详细解释和示例代码。
1. useState
用途:useState
用于在函数组件中添加本地状态。这个状态在组件的多次渲染之间是被保持的,它返回一个状态变量和一个更新这个状态变量的函数。
基本用法
useState
接受初始状态作为参数,并返回一个包含两个元素的数组。- 第一个元素是当前的状态值,第二个元素是一个允许你更新该状态的函数。
特点
- 使用
useState
,你可以在函数组件中添加和读取状态,而无需将组件转换为类。 - 状态的更新可能是异步的,React 可能会延迟或合并多次
setState()
调用以优化性能。
示例代码:
jsx
import React, { useState } from 'react';
function Example() {
// 声明一个新的状态变量,我们将其称为 "count"
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
import React, { useState } from 'react';
function Example() {
// 声明一个新的状态变量,我们将其称为 "count"
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
伪代码
jsx
function useState(initialValue) {
// 获取当前组件的上下文
const currentComponent = React.__currentComponent;
// 获取下一个状态钩子的索引
const hookIndex = currentComponent.__nextHookIndex++;
// 首次渲染时,设置初始值
if (currentComponent.__isFirstRender) {
// 初始化状态和更新函数
currentComponent.__hooks[hookIndex] = {
state: initialValue,
queue: []
};
}
// 获取当前的钩子
const hook = currentComponent.__hooks[hookIndex];
// 如果有更新排队,应用这些更新
hook.queue.forEach(update => {
hook.state = update(hook.state);
});
// 清空更新队列
hook.queue = [];
// setState函数,用于更新状态
const setState = (newState) => {
// 将更新函数加入队列
hook.queue.push(newState instanceof Function ? newState : () => newState);
// 触发组件的重新渲染
React.__scheduleRender(currentComponent);
};
// 返回状态值和更新状态的函数
return [hook.state, setState];
}
function useState(initialValue) {
// 获取当前组件的上下文
const currentComponent = React.__currentComponent;
// 获取下一个状态钩子的索引
const hookIndex = currentComponent.__nextHookIndex++;
// 首次渲染时,设置初始值
if (currentComponent.__isFirstRender) {
// 初始化状态和更新函数
currentComponent.__hooks[hookIndex] = {
state: initialValue,
queue: []
};
}
// 获取当前的钩子
const hook = currentComponent.__hooks[hookIndex];
// 如果有更新排队,应用这些更新
hook.queue.forEach(update => {
hook.state = update(hook.state);
});
// 清空更新队列
hook.queue = [];
// setState函数,用于更新状态
const setState = (newState) => {
// 将更新函数加入队列
hook.queue.push(newState instanceof Function ? newState : () => newState);
// 触发组件的重新渲染
React.__scheduleRender(currentComponent);
};
// 返回状态值和更新状态的函数
return [hook.state, setState];
}
2. useEffect
用途:用于在组件渲染到屏幕之后执行副作用操作(如数据获取、订阅或手动更改 React 组件中的 DOM)。
示例代码:
jsx
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
伪代码
jsx
function useEffect(effectFunction, dependencies) {
const currentComponent = React.__currentComponent;
const hookIndex = currentComponent.__nextHookIndex++;
const lastDependencies = currentComponent.__hooks[hookIndex]?.lastDependencies;
// 检查依赖是否发生变化
const hasChanged = lastDependencies === undefined || dependencies.some((dep, i) => dep !== lastDependencies[i]);
if (hasChanged) {
// 清理上一次的副作用(如果存在)
if (currentComponent.__hooks[hookIndex]?.cleanup) {
currentComponent.__hooks[hookIndex].cleanup();
}
// 执行副作用函数
currentComponent.__hooks[hookIndex] = {
lastDependencies: dependencies,
cleanup: effectFunction()
};
}
}
function useEffect(effectFunction, dependencies) {
const currentComponent = React.__currentComponent;
const hookIndex = currentComponent.__nextHookIndex++;
const lastDependencies = currentComponent.__hooks[hookIndex]?.lastDependencies;
// 检查依赖是否发生变化
const hasChanged = lastDependencies === undefined || dependencies.some((dep, i) => dep !== lastDependencies[i]);
if (hasChanged) {
// 清理上一次的副作用(如果存在)
if (currentComponent.__hooks[hookIndex]?.cleanup) {
currentComponent.__hooks[hookIndex].cleanup();
}
// 执行副作用函数
currentComponent.__hooks[hookIndex] = {
lastDependencies: dependencies,
cleanup: effectFunction()
};
}
}
3. useContext
用途:允许你在组件树中共享数据而不必显式地通过每个层级传递 props。
示例代码:
jsx
import React, { useContext } from 'react';
const MyContext = React.createContext();
function Example() {
const value = useContext(MyContext);
return <div>{value}</div>;
}
import React, { useContext } from 'react';
const MyContext = React.createContext();
function Example() {
const value = useContext(MyContext);
return <div>{value}</div>;
}
伪代码
jsx
function useContext(context) {
// 获取当前组件的上下文
const currentComponent = React.__currentComponent;
// 检索上下文的当前值
const contextValue = React.__getContextValue(context);
// 组件订阅上下文的变化
React.__subscribeToContext(context, currentComponent);
// 返回上下文的当前值
return contextValue;
}
function useContext(context) {
// 获取当前组件的上下文
const currentComponent = React.__currentComponent;
// 检索上下文的当前值
const contextValue = React.__getContextValue(context);
// 组件订阅上下文的变化
React.__subscribeToContext(context, currentComponent);
// 返回上下文的当前值
return contextValue;
}
4. useReducer
用途:用于更复杂的组件状态逻辑,它接受一个状态更新的函数和初始状态,返回当前的状态和一个让你能够触发状态更新的 dispatch 方法。
示例代码:
jsx
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 (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
</>
);
}
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 (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
</>
);
}
伪代码
jsx
function useReducer(reducer, initialState) {
// state 用于存储当前状态
let state = initialState;
// dispatch 函数用于触发状态更新
const dispatch = (action) => {
// 调用 reducer 函数来计算新状态
state = reducer(state, action);
// 这里简化了更新组件的逻辑。
// 在真实的 React useReducer 中,会触发组件的重新渲染
};
// 返回当前状态和 dispatch 函数
return [state, dispatch];
}
// reducer 函数定义了如何响应不同的动作并更新状态
function reducer(state, action) {
switch (action.type) {
case 'increment':
return state + 1;
case 'decrement':
return state - 1;
default:
throw new Error();
}
}
// 使用 useReducer
const [state, dispatch] = useReducer(reducer, 0);
// 触发状态更新
dispatch({ type: 'increment' }); // state 现在是 1
dispatch({ type: 'decrement' }); // state 现在是 0
function useReducer(reducer, initialState) {
// state 用于存储当前状态
let state = initialState;
// dispatch 函数用于触发状态更新
const dispatch = (action) => {
// 调用 reducer 函数来计算新状态
state = reducer(state, action);
// 这里简化了更新组件的逻辑。
// 在真实的 React useReducer 中,会触发组件的重新渲染
};
// 返回当前状态和 dispatch 函数
return [state, dispatch];
}
// reducer 函数定义了如何响应不同的动作并更新状态
function reducer(state, action) {
switch (action.type) {
case 'increment':
return state + 1;
case 'decrement':
return state - 1;
default:
throw new Error();
}
}
// 使用 useReducer
const [state, dispatch] = useReducer(reducer, 0);
// 触发状态更新
dispatch({ type: 'increment' }); // state 现在是 1
dispatch({ type: 'decrement' }); // state 现在是 0
5. useRef
用途:用于获取对 DOM 元素的直接访问,或者存储任何可变值,该值不会导致组件重新渲染。
示例代码:
jsx
import React, { useRef } from 'react';
function TextInputWithFocusButton() {
const inputEl = useRef(null);
onButtonClick = () => {
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
import React, { useRef } from 'react';
function TextInputWithFocusButton() {
const inputEl = useRef(null);
onButtonClick = () => {
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
伪代码
jsx
function useRef(initialValue) {
// useRef 使用一个对象来存储引用的值,这个对象有一个叫做 'current' 的属性
const refObject = { current: initialValue };
// 返回这个对象
return refObject;
}
// 使用 useRef
const myRef = useRef(0);
// 访问 ref 的值
console.log(myRef.current); // 输出 0
// 更新 ref 的值
myRef.current = 10;
// 再次访问 ref 的值
console.log(myRef.current); // 输出 10
function useRef(initialValue) {
// useRef 使用一个对象来存储引用的值,这个对象有一个叫做 'current' 的属性
const refObject = { current: initialValue };
// 返回这个对象
return refObject;
}
// 使用 useRef
const myRef = useRef(0);
// 访问 ref 的值
console.log(myRef.current); // 输出 0
// 更新 ref 的值
myRef.current = 10;
// 再次访问 ref 的值
console.log(myRef.current); // 输出 10
6. useMemo
用途:用于优化性能,它可以记住一个计算得出的值,并且只有在其依赖项改变时才重新计算。
示例代码:
jsx
import React, { useMemo } from 'react';
function Example({ a, b }) {
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
return <div>{memoizedValue}</div>;
}
import React, { useMemo } from 'react';
function Example({ a, b }) {
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
return <div>{memoizedValue}</div>;
}
7. useCallback
用途:返回一个记忆化的回调函数,该回调函数仅在某个依赖项改变时才会更新。
示例代码:
jsx
import React, { useCallback } from 'react';
function Example({ onIncrement }) {
const memoizedCallback = useCallback(
() => {
onIncrement();
},
[onIncrement],
);
return <button onClick={memoizedCallback}>Increment</button>;
}
import React, { useCallback } from 'react';
function Example({ onIncrement }) {
const memoizedCallback = useCallback(
() => {
onIncrement();
},
[onIncrement],
);
return <button onClick={memoizedCallback}>Increment</button>;
}
伪代码
jsx
function useMemo(factory, deps) {
// 用于存储记忆化值的变量
let memoizedValue;
// 用于存储依赖数组的上一次值的变量
let oldDeps = deps;
if (depsChanged(oldDeps, deps)) {
// 如果依赖项改变了,重新计算值
memoizedValue = factory();
oldDeps = deps;
}
// 返回记忆化的值
return memoizedValue;
}
function depsChanged(oldDeps, deps) {
// 比较旧的依赖项和新的依赖项,判断它们是否相等
// 这里简化了实际的比较逻辑
return oldDeps !== deps;
}
// 使用 useMemo
const expensiveValue = useMemo(() => {
// 进行复杂计算
return computeExpensiveValue(a, b);
}, [a, b]);
// computeExpensiveValue 只会在 a 或 b 改变时重新计算
function useMemo(factory, deps) {
// 用于存储记忆化值的变量
let memoizedValue;
// 用于存储依赖数组的上一次值的变量
let oldDeps = deps;
if (depsChanged(oldDeps, deps)) {
// 如果依赖项改变了,重新计算值
memoizedValue = factory();
oldDeps = deps;
}
// 返回记忆化的值
return memoizedValue;
}
function depsChanged(oldDeps, deps) {
// 比较旧的依赖项和新的依赖项,判断它们是否相等
// 这里简化了实际的比较逻辑
return oldDeps !== deps;
}
// 使用 useMemo
const expensiveValue = useMemo(() => {
// 进行复杂计算
return computeExpensiveValue(a, b);
}, [a, b]);
// computeExpensiveValue 只会在 a 或 b 改变时重新计算