个人对React Hooks的理解(一)
这是个人对React Hooks的理解 以及部分原理解析。内容可能不完全正确,仅供参考。
React Hooks
useState
useState是React提供的一个用于管理状态的Hook。 它接收一个初始值,并返回一个数组,数组中包含两个元素:一个是当前状态值,一个是更新状态的函数。
const [count, setCount] = useState(0);
1. 它出现解决了什么问题
- 在React中,状态管理是一个非常重要的问题。在React 16.8之前,状态管理通常使用类组件来实现。类组件虽然可以管理状态,但是存在一些问题:
- 状态逻辑难以复用
- 状态逻辑难以维护
- 状态逻辑难以理解
- 状态逻辑难以调试
- 状态逻辑难以优化 useState的出现让这些变得简单,更容易维护和理解。
2. useState的state到底存放在哪?它是怎么做到响应式的?
- React的每个Hook都有一个对应的Fiber节点,Fiber节点中有一个memoizedState属性,它是一个链表(你也可以叫它列表),链表中存储了当前组件的Hook。
// 伪代码 大概就是长这样
const fiber = {
stateNode: myComponentInstance, // 组件实例 (如函数组件或类组件的实例)
type: 'function', // 组件类型(函数组件、类组件、DOM 元素等)
props: { count: 5 }, // 组件的 props
memoizedState: { // 存储 Hook 状态(每个 Hook 的缓存值)
hook1: { value: 0 }, // 例如 useState(0)
hook2: { value: "Alice" }, // 例如 useState("Alice")
},
effectTag: 'UPDATE', // 更新类型(例如更新、插入、删除等)
nextEffect: null, // 下一个 effect 节点(用于链式处理副作用)
updateQueue: [], // 更新队列(例如状态更新)
return: parentFiber, // 父组件的 fiber 节点
child: childFiber, // 子组件的 fiber 节点
};
- 当我们每次调用setState的时候,React会遍历Fiber节点,检查每个memoizedState的旧值是否发生变化,如果发生变化,则更新状态,并调用组件的更新函数。
- 所以说我们每次修改值,都会触发组件的更新。这样组件频繁的更新,就会导致性能问题。然而React.memo() 和 useMemo() 的出现,让我们可以优化组件的渲染。
useMemo
useMemo是React提供的一个用于记忆化计算的Hook。 它接收一个计算函数和依赖数组,当依赖数组中的值发生变化时,会重新计算计算函数的值,并返回新的值。
1. 它出现解决了什么问题?
- 避免重复计算昂贵的计算
- 避免组件的频繁渲染
- 提高组件的性能
2. 它是怎么做到的?
- 当依赖数组中的值发生变化时,会重新计算计算函数的值,并返回新的值。
- 当依赖数组中的值没有发生变化时,会返回缓存中的值。
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
const computeExpensiveValue = (a, b) => {
return a + b;
}
- 当依赖数组中的值a、b发生变化时,会重新计算计算函数的值,并返回新的值。
- 当依赖数组中的值a、b没有发生变化时,会返回缓存中的值。 当子组件引用了useMemo的值,当父组件的值发生变化时,子组件不会重新渲染。这样就解决了性能问题。
const Child = React.memo(({ memoizedValue }) => {
return <div>{memoizedValue}</div>;
});
3.useState配合useEffect不也能实现昂贵的计算吗?
- 是的,useState配合useEffect也能实现昂贵的计算。 但是有个问题,useEffect的执行时机是组件挂载后和每次更新后,而不是组件渲染时就执行的。这就导致我们Effect实现的memo会在组件挂载后才进行计算,会有效率问题。 再就是写很多的Effect,会让代码变得臃肿,难以维护。
const [count, setCount] = useState(0);
useEffect(() => {
setCount(computeExpensiveValue(a, b));
}, [a, b]);
React.memo() 和 useMemo()
- React.memo() 是React提供的一个用于记忆化计算的组件。
- useMemo() 是React提供的一个用于记忆化计算的Hook。
- React.memo() 是用于组件的记忆化计算,而useMemo() 是用于状态的记忆化计算。
- React.memo() 和 useMemo()都是会对组件props进行浅比较也就是内存地址的比较,如果props没有发生变化,则不会重新渲染组件。
const Child = React.memo(({ props }) => {
return <div>{props.count}</div>;
});