useIsMounted 的实现
2种实现方式对比,深入对 react 的了解
场景
isMounted 的实现,这个 hoook 重命名为
useStaticMounted
/useMountedFlag/useMountTracker
import { useEffect, useRef } from 'react';
const useIsMounted = () => {
const isMounted = useRef(false);
useEffect(() => {
isMounted.current = true;
return () => {
isMounted.current = false;
};
}, []);
return isMounted.current;
};
export default useIsMounted;
使用 useState
import { useEffect, useState } from 'react';
const useIsMounted = () => {
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
setIsMounted(true);
return () => setIsMounted(false);
}, []);
return isMounted;
};
export default useIsMounted;
2种方式对比
在实现 `useIsMounted` 这个 Hook 时,直接使用 `useRef` 是更合适的选择,而不是使用 `useState`。原因如下:
### 1. **`useRef` vs `useState` 性能开销**
- **`useRef`**: 它的 `.current` 属性在组件重新渲染时不会改变,因此不触发重新渲染。
- **`useState`**: 状态更新会触发组件重新渲染。如果用 `useState` 实现 `isMounted`,状态的更新会导致额外的重新渲染,这是没有必要的。
### 2. **功能需求**
- `useIsMounted` 的需求是追踪组件的挂载状态,而不是动态触发渲染。`useRef` 的设计正好适合这种“保存某个值而不参与渲染逻辑”的场景。
- 如果用 `useState`,状态更新的触发会违背它的初衷,增加不必要的复杂性。
### `useState` 实现的对比示例
用 `useState` 实现可能像这样:
```javascript
import { useEffect, useState } from 'react';
const useIsMounted = () => {
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
setIsMounted(true);
return () => setIsMounted(false);
}, []);
return isMounted;
};
export default useIsMounted;
```
### 缺点
- 每次状态更新都会触发组件的重新渲染,即使 `isMounted` 的值没有在渲染中直接使用。
- 在一些性能敏感的场景下(如高频渲染组件),可能引入性能问题。
### 总结
你当前的实现基于 `useRef` 是更合理的。`useState` 适合管理需要触发重新渲染的值,而 `useRef` 则适合保存不会影响渲染的值。你的代码完全符合最佳实践,无需改用 `useState`。
更优的写法
export function useIsMounted(): () => boolean {
const isMounted = useRef(false)
useEffect(() => {
isMounted.current = true
return () => {
isMounted.current = false
}
}, [])
return useCallback(() => isMounted.current, [])
}