You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
importReact,{useState}from'react';functionExample(){// Declare a new state variable, which we'll call "count"const[count,setCount]=useState(0);return(<div><p>You clicked {count} times</p><buttononClick={()=>setCount(count+1)}>
Click me
</button></div>);}
看到onClick绑定的那个匿名函数了吗?这样写的话,每次 render 的时候都会重新生成一个新的函数。这在之前可能不需要太在意,因为我们一般只是拿 Function Component 来实现一些展示型组件,在其之下不会有太多的子组件。但是如果我们拥抱 Hooks 之后,那么就不可控了。
虽然说在一般情况下,这并不会造成太大的性能问题,而且 Function Component 本身的性能就要比 Class Component 更好一点,但是难免会碰到需要优化的时候,比方说在重构原来的 Class Component 的时候,其中有个子组件是个PureComponent,便会使子组件的这个优化失效 ,那么怎么解决呢?
functionmountWorkInProgressHook(): Hook{consthook: Hook={memoizedState: null,baseState: null,queue: null,baseUpdate: null,next: null,};if(workInProgressHook===null){// This is the first hook in the listfirstWorkInProgressHook=workInProgressHook=hook;}else{// Append to the end of the listworkInProgressHook=workInProgressHook.next=hook;}returnworkInProgressHook;}
在上一篇文章中,我们谈到 Hooks 给 React 带来的一些在开发体验上的改变,如果你已经开始尝试 React Hooks,也许你会跟我一样碰到一个令人疑惑的地方,如果没有的话,那就再好不过啦,我就权当做个记录,以便他人之需。
如何绑定事件?
我们先以官方的例子开始:
看到
onClick
绑定的那个匿名函数了吗?这样写的话,每次 render 的时候都会重新生成一个新的函数。这在之前可能不需要太在意,因为我们一般只是拿 Function Component 来实现一些展示型组件,在其之下不会有太多的子组件。但是如果我们拥抱 Hooks 之后,那么就不可控了。虽然说在一般情况下,这并不会造成太大的性能问题,而且 Function Component 本身的性能就要比 Class Component 更好一点,但是难免会碰到需要优化的时候,比方说在重构原来的 Class Component 的时候,其中有个子组件是个
PureComponent
,便会使子组件的这个优化失效 ,那么怎么解决呢?使用
useCallback
或useMemo
来保存函数的引用,避免重复生成新的函数可见
useCallback(fn, inputs)
等同于useMemo(() => fn, inputs)
,那么这两个 Hook 具体是怎么做到的呢?我们可以从源码中一窥究竟,我们以useCallback
为例(useMemo
大体上都是一样的,就返回值不同,后面会提到)。首先,在第一次执行
useCallback
时,React内部会调用ReactFiberHooks
中的mountCallback
,之后再次执行时调用的都是updateCallback
,具体代码可以看这里:https://github.com/facebook/react/blob/master/packages/react-reconciler/src/ReactFiberHooks.js#L974我们一点点来看,先看下
mountCallback
:发现核心在于
mountWorkInProgressHook
这个方法代码比较简单,就不一一解释了,从上面的代码我们可以得知 Hooks 的本体:
我们主要关注
memoizedState
和next
,memoizedState
在不同的 Hook 中存放的值会有所不同,在useCallback
中存的就是入参的值[callback, deps]
,next
的值就是下一个 hook,也就是说 Hooks 其实就是一个单向链表,这也就解释了为什么 Hooks 需要在顶层调用,不能在循环、条件语句、嵌套函数中使用,因为需要保证每次调用的顺序一致。再来看之后的
updateCallback
:useMemo
的实现与useCallback
类似,大概看一下:由以上代码便可以看出
useCallback
和useMemo
在用法上的区别了。除了这两个方法以外,还可以通过
context
来传递由useReducer
生成的dispatch
方法,来避免直接传递callback
,因为dispatch
是不变的。这个方法跟前面两种有本质上的区别,它从源头上就阻止了callback的传递,所以也就不会有前面提到的性能方面的顾虑,这也是官方推荐的方法,特别是组件树很大的情况下。所以上面的代码如果通过这种方式来写的话,就会是下面这样,有点像Redux
:总结
useCallback
或useMemo
来优化。callback
的层级可能会很深,可以通过useReducer
配合context
来处理。The text was updated successfully, but these errors were encountered: