【React Hooks 的原理 - CSDN App】http://t.csdnimg.cn/DPzj6
浅浅笔记一下,其中关于 a = b.next = c 这一段,应该是fiber节点已经持有了对象b。c是新的hook节点,b.next 指向新节点,在链表尾部添加新节点,然后通过a返回。
关于memorizedState,在fiber节点上存在memorizedState属性,该属性指向hook链表的头节点;每个hook节点中又持有各自的memorizedState属性,hook节点上的该属性指向该hook节点对应的值,比如useref的ref.current的值。
【一文搞懂useCallback的使用 - CSDN App】http://t.csdnimg.cn/Gdvs4
关于usecallback的作用,以及什么时候使用,可以参考下这篇。usecallback的作用在于保证两次render前后的function函数是同一个函数。
如果子组件使用usememo包裹,该function传递给子组件,子组件在function每次更新时都会render。因为每次更新时,function都会被重新创建,两次传入的function是在两片不同的内存空间,子组件还是会触发一次render。
usecallback的作用在于保证每次返回同一个function,避免在usememo后还是触发了多次渲染。
usecallback只是返回同一个function,并没有阻止函数对象的创建,所以依然会有创建函数对象的开销;同时还会有监听依赖的开销、hooks挂载的开销、hooks更新的开销;在使用时需要注意是否确实需要。
同时,由于usecallback在监听到依赖项(usecallback第二个入参)变化时,才会返回新的function,需要注意function更新的时机,注意function跟随依赖项更新。
比如usestate和usecallback同时使用时,如果不添加对state对象的监听,callback函数中使用的永远是初始化时的state。具体可以参考闭包的场景,usecallback返回的function内部使用的永远是function创建时的state,也就是初始的state。
usestate的state在每次render更新时,都是一个新的变量,指向一片内存空间(假设初始对象是一个object)。
第一次render,第一次执行组件对应的函数,记state是state1,function创建,function内部使用了state1;
然后执行setstate操作;
此时第二次render,第二次执行组件对应的函数,记state是state2,function还是第一次的function,没有使用新创建的function,function内部还是指向state1。
如此,在业务代码执行时,就会出现一直是state1的场景。
import React, { useCallback, useState } from 'react'
export default function App() {
const [count, _setCount] = useState(0)
const setCountWithCb = useCallback(
() => {
_setCount(count + 1)
},
[],
)
const setCount = () => {
_setCount(count + 1)
}
return (
<div>
<div onClick={() => setCount()}>{count}</div>
<ChildB onClickAdd={() => {setCountWithCb()}}/>
</div>
)
}
const ChildB = function({onClickAdd}) {
console.log('render B')
return <div onClick={() => onClickAdd()}>Add</div>
}
题外,函数式组件本身就是一个函数,用来更新render树的一次性函数,不存在任何状态留存。hooks通过在fiber节点上挂载额外属性memorizedstte的方式,让函数式组件能够通过fiber读取到上一次render的值,实现和类式组件一样的效果。
函数式组件对比类式组件,优势在于不需要维护class实例,开销较小,可以类似将函数式组件看作创建/更新fiber节点的一次性道具,用完就抛弃。同时函数式组件相比类式组件,会减少一些模版代码。
个人观感,函数式组件的缺憾在于hooks的写法会导致稍大型的页面,在数据更新和管理方面很错杂。随处可见的useeffect监听和usecallback等会让数据的流转过程变得细碎,没有统一的事件流来跟踪、执行数据变化,以及处理该变化带来的副作用,会增加业务的复杂度,影响阅读和维护。
个人观感,对于通用的、内容自洽的业务组件、交互组件可以通函数式组件封装,起到随装随用的作用。而对于复杂页面,使用类式组件统一处理业务逻辑,在其中可以穿插使用函数式组件封装的通用的轮子。在实现业务的情况下,尽可能保证项目的可读性、可维护性,方便后续迭代。