react中的hook
在 React 中,Hooks 是一种在函数组件中使用状态和其他 React 特性(如生命周期方法)的新方式。它们在 React 16.8 中被引入,并且极大简化了组件的状态管理和副作用处理。
常见的 React Hook
- useState
- useEffect
- useContext
- useReducer
- useRef
- useMemo
- useCallback
- useLayoutEffect
- useImperativeHandle
1. useState
useState
是最基本的 Hook,用于在函数组件中添加状态。
示例:
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0); // count 为状态变量,setCount 为更新该状态的函数
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
export default Counter;
useState(0)
中的0
是初始状态值。setCount
是更新状态的方法。
2. useEffect
useEffect
用于处理副作用,类似于类组件中的生命周期方法(如 componentDidMount
, componentDidUpdate
, componentWillUnmount
)。
示例:
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// 组件挂载时运行
useEffect(() => {
console.log('Component mounted or count changed!');
document.title = `You clicked ${count} times`;
// 返回的函数是清理函数,在组件卸载时调用
return () => {
console.log('Cleanup for count change!');
};
}, [count]); // 依赖数组,表示只有当 count 改变时才执行副作用
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
export default Example;
useEffect
第一个参数是一个副作用函数,第二个参数是依赖数组。- 如果依赖数组为空(
[]
),副作用函数只会在组件挂载和卸载时执行。
3. useContext
useContext
用于在函数组件中访问 React 上下文(Context)中的值。
示例:
import React, { useContext } from 'react';
// 创建上下文
const MyContext = React.createContext('default value');
function Example() {
const value = useContext(MyContext); // 访问上下文值
return <div>{value}</div>;
}
function App() {
return (
<MyContext.Provider value="Hello, world!">
<Example />
</MyContext.Provider>
);
}
export default App;
useContext(MyContext)
用于获取MyContext
提供的值。
4. useReducer
useReducer
是一种更复杂的状态管理方式,类似于 useState
,但是它适用于处理复杂的状态逻辑,尤其是有多个子状态的情况。它通常用于处理复杂的状态更新逻辑,或者在 React 应用中使用类似 Redux 的模式。
示例:
import React, { useReducer } from 'react';
// 定义 reducer 函数
function counterReducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(counterReducer, { count: 0 });
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
接受两个参数:reducer 函数和初始状态。dispatch
是用于触发reducer
更新状态的函数。
5. useRef
useRef
用于获取 DOM 元素的引用或者持久化值。在重新渲染时,useRef
不会导致组件重新渲染,它常用于访问 DOM 元素或保持跨渲染周期不变的值。
示例:
import React, { useRef } from 'react';
function FocusInput() {
const inputRef = useRef();
const focusInput = () => {
inputRef.current.focus(); // 让 input 元素获取焦点
};
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={focusInput}>Focus the input</button>
</div>
);
}
export default FocusInput;
useRef
返回一个对象,该对象的current
属性指向 DOM 元素或任何可变值。
6. useMemo
useMemo
用于缓存计算结果,以避免不必要的重新计算。它只会在依赖项发生变化时重新计算结果。
示例:
import React, { useMemo } from 'react';
function Example({ num }) {
const expensiveComputation = (num) => {
console.log('Computing...');
return num * 2;
};
const computedValue = useMemo(() => expensiveComputation(num), [num]);
return <div>{computedValue}</div>;
}
export default Example;
useMemo
通过依赖数组来优化性能,避免在每次渲染时执行高昂的计算。
7. useCallback
useCallback
用于返回一个 memoized 版本的回调函数,只有当依赖项发生变化时才会更新。它常用于将回调函数传递给子组件,以避免不必要的重新渲染。
示例:
import React, { useCallback, useState } from 'react';
function Button({ onClick }) {
return <button onClick={onClick}>Click me</button>;
}
function Parent() {
const [count, setCount] = useState(0);
const increment = useCallback(() => setCount(count + 1), [count]);
return (
<div>
<Button onClick={increment} />
<p>Count: {count}</p>
</div>
);
}
export default Parent;
useCallback
确保increment
函数只有在count
改变时才会重新创建。
8. useLayoutEffect
useLayoutEffect
和 useEffect
类似,不同之处在于它会在 DOM 更新之前同步执行。通常用于读取布局和同步触发副作用。
示例:
import React, { useLayoutEffect, useState } from 'react';
function LayoutExample() {
const [width, setWidth] = useState(0);
useLayoutEffect(() => {
setWidth(window.innerWidth);
}, []);
return <div>Window width: {width}</div>;
}
export default LayoutExample;
useLayoutEffect
在 DOM 更新后立即执行,通常用于在页面渲染之前进行一些测量。
9. useImperativeHandle
useImperativeHandle
用于自定义暴露给父组件的实例值。通常与 forwardRef
配合使用,用于在函数组件中暴露 ref。
示例:
import React, { useImperativeHandle, forwardRef, useRef } from 'react';
const MyComponent = forwardRef((props, ref) => {
const localRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
localRef.current.focus();
}
}));
return <input ref={localRef} />;
});
function Parent() {
const inputRef = useRef();
const focusInput = () => {
inputRef.current.focus(); // 使用子组件暴露的 focus 方法
};
return (
<div>
<MyComponent ref={inputRef} />
<button onClick={focusInput}>Focus the input</button>
</div>
);
}
export default Parent;
useImperativeHandle
用于控制外部组件访问的实例值。
总结
React 的 Hook 提供了许多强大的功能,使函数组件能够处理状态、生命周期、引用等。掌握这些常用的 Hook,能够帮助你在开发中写出更加简洁、可维护的代码。