在最初学习react的时候,我们大部分会选择去扒一扒React的官方文档,看看他是什么,怎么使用的。而我却很好奇在文档里学习的第一个完整的组件是 类(Class)组件,但是在实际工作中我们看到项目中所声明的组件都是以函数的形式所展示的。于是一个小小的疑问引起了我对新知识的探索。原来随着项目的发展,组件会被越来越多复杂的状态逻辑和副作用充斥,对于例如事件的监听移除这种成对出现的逻辑被拆分到不同的方法中,而又有很多完全不相关的代码却组合在了一起,就会产出许多的bug。甚至在项目打包Class不能很好的被压缩,并会使热重载出现不稳定的情况等等…Facebook的工程师们想到一个很好的替代方案引入一个API,让函数组件拥有Class组件一样的状态管理的能力,和完整的生命周期函数。他就是Hook。但是我们依旧可以继续使用Class组件。
Hook是React16.8新增的特性,目的就是为了让开发者在不编写Class的情况下使用state,实现组件的生命周期,Ref以及其他的React特性。
举个例子:
推荐一个博主编写的极简实现useState的博客:React技术揭秘 里边讲述了react useState底层实现的原理。然后配合 GitHub - acdlite/react: A declarative, efficient, and flexible JavaScript library for building user interfaces. React源码尝试着理解Hook理念。
例如一般我们定义一个state变量
const [count , setCount] = useState(initValue);
initValue:就是设定初始的值
setCount的使用有两种情况
setCount( newValue ); //参数为非函数值时,直接指定新的状态值
setCount( oldValue =>{ … return newValue} ) //参数为函数时,接收原本的状态值,通过函数返回新的状态值
一个升级版的useState,在某些场景下useRucer会比useSate更适用,例如state逻辑比较复杂且包含多个子值,或者下一个state依赖之前的state等。 原理类似redux,需要reducer 、action、dispatherinitValue:就是设定初始的值
可以把useEffect 看做如下三个函数的组合
componentDidMount( );
componentDidUpdate( );
componentWillUnmount( );
useEffect( ( )=>{ }) ; //监听所有useState变量的变化
useEffect( ( )=>{
return ( ) => { //相当于componentWillUnmount }
}) ;
useEffect( ()=>{} , [ ] ) ; //不监听任何变量 且函数只会在第一次 render( ) 后执行
useEffect( ( )=>{ } , [name,list]) ; //监听name list变量的变化
const inputEL = useRef( ); 声明一个标记容器
<input type="text" ref={ inputEL } />
inputEL.current.focus( );
inputEL.current.blur( );
我们用useCallback把函数包起来之后,在父组件中只有当Text, isKey变化的时候,才会创建新的handleIneerHTML实例,子组件才会跟着reRender
如果useMemo(fn, arr)第二个参数匹配,并且其值发生改变,才会多次执行执行,否则只执行一次,如果为空数组[],fn只执行一次
useMemo和useCallback都是reactHook提供的两个API,用于缓存数据,优化性能;两者接收的参数都是一样的,第一个参数表示一个回调函数,第二个表示依赖的数据。
共同的作用:在依赖数据发生变化的时候,才会调用传进去的回调函数去重新计算结果,起到一个缓存的作用
两者的区别:useMemo 缓存的结果是回调函数中return回来的值,主要用于缓存计算结果的值,应用场景如需要计算的状态
useCallback 缓存的结果是函数,主要用于缓存函数,应用场景如需要缓存的函数,因为函数式组件每次任何一个state发生变化,会触发整个组件更新,一些函数是没有必要更新的,此时就应该缓存起来,提高性能,减少对资源的浪费;另外还需要注意的是,useCallback应该和React.memo配套使用,缺了一个都可能导致性能不升反而下降。
TextComponent组件
Buttons组件