class组件编译es5后会多出一大坨辅助函数(继承React.Component),而fc组件只有一个createElement。useMemo、useCallback、useEffect等有deps参数的Hook API都依赖Fiber.memoizedState属性(存储结果),它们用来优化纯函数组件的渲染,相同输入直接返回记忆中的结果(用空间换时间,当然要设置最大空间限制),即多次render如果deps有记录则忽略此次执行直接返回对应的缓存。
useMemo用于相对组件同步执行,useCallback用于异步执行,useEffect用于处理组件副作用。
总之因为纯函数确定输入总是返回确定输出的特性会有很多种优化手段,除了memorization还有例如inline expansion,因为纯函数无副作用所以线程安全,可以使用多核来并行计算,虽然JS引擎是单线程,但是浏览器提供了WebWorkers。。(又扯远了,不说了)函数组件内的Hook调用可以抽离出来写成一个Custom Hook,尽量保证主体组件内视图层占主要,逻辑全部封装到Custom Hook里。
而class组件不能使用Hook API,所以想要在class component外部访问到setState(ReactDispatcher),需要利用回调函数,或者是发布订阅,比如加个Redux,通过调用store dispatch间接调用到setState。
所以现在函数组件可以去掉redux了。
(如果想要thunk的话,自己把useReducer dispatch封装一下)所以class组件的画风就是@connect、mapXXXToProps、subscribe、dispatch还有各种生命周期钩子,而函数组件清一色的useState,useReducer,useEffect,useXXX,setState。(你觉得哪个看起来清爽?哪个可读性更高?)state.values做useCallback的deps,只有当state.values发生变化,callback才会重新执行,否则返回上次执行的值。关于这个问题,先看看react useMemo Hook 源码怎么样?useMemo 即 updateMemo的实现deps比较areHookInputsEqualobject-is比较算法所以对象做为memorization deps就有问题。JS中 === 比较的是栈上的指针地址。(没有operator overload的语言能怎么办,当然你可以写一个deep版本的_.isEqual把react的那个换掉)
state.values做useCallback的deps,只有当state.values发生变化,callback才会重新执行,否则返回上次执行的值。关于这个问题,先看看react useMemo Hook 源码怎么样?
useMemo 即 updateMemo的实现
deps比较areHookInputsEqualobject-is比较算法所以对象做为memorization deps就有问题。
JS中 === 比较的是栈上的指针地址。(没有operator overload的语言能怎么办,当然你可以写一个deep版本的_.isEqual把react的那个换掉)
1 === 1 // true
{id: 1} === {id: 1} // false
Object.is(1, 1) // true
Object.is({id: 1}, {id: 1}) // false