前言 react-hook 是 16.8 版本之后为组件函数提供 state 功能的工具。关于诸多介绍,详细看文档了,下面只讲述我在项目的实际使用。
react-hook 诞生目的 根据官方的说法,多年用 class 编写组件,发现其中逻辑的复用并不高,尽管有 renderProps 和高阶组件解决方案,但终究不够优雅,组件间嵌套的层数,一不小心就会让人深陷泥潭。为此官方一直寻找一个方式,更大的复用组件中的一些 state 以及耦合的逻辑,由此 react-hook 诞生出来了,当然 react-hook 也不仅仅是逻辑间的复用,还有 state 组织方式,以及类式 class 生命周期的 useEffect hook。
useEffect useEffect 这个 hook,里面的门道一点也不简单,目前在项目中使用场景也非常简单,只是在里面处理异步的请求,后续会补充其更多的使用场景。详情请看下面两个链接:
https://overreacted.io/zh-hans/making-setinterval-declarative-with-react-hooks/ 
https://overreacted.io/zh-hans/a-complete-guide-to-useeffect/ 
https://www.robinwieruch.de/react-hooks-fetch-data/ 
useEffect 集合了类式 class 组件的生命周期 componentDidMount(),componentWillUnMount() componentDidUpdate()。
自定义的 hook 大大提升复用率,自定义的 hook 是什么呢,在我看来,它就是一个函数,你可以往里面传一些参数,里面有一个自己的 state,然后返回一个 state 就行了。看下面我封装的代码就可以明白这一点
项目中的使用 在最近的重构项目中使用 react-hook,react-hook 不仅赋予了函数组件 state 的能力,而且一个强大之处就是对 state 的复用,这点深有体会。用了 react-hook 不仅代码函数大大缩减,而且可以对不同的 state 声明,以及操作进行划分设置,最厉害的就是复用率大大提升。下面就放上项目封装的 request hook
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function  useRequestData (params ) {   const  [data, setData] = useState ();   const  fetchData  = ( ) => {          request.post (params).then (res  =>  {       setData (res.data );     });   };   useEffect (() =>  {     fetchData ();   }, []);      return  [data, fetchData]; }
 
useCallback的使用场景 使传递给子组件的函数保持meroize化,这样可以使子组件不必重新渲染。来看一个example
1 2 3 4 5 6 7 8 9 10 11 12 function  Hello ({onClick} ){   return  <button  onClick ={onClick} > example text</button >  }function  App ( ){    const   onClick =( )=>{     }          return  <Hello  onClick ={onClick}/ >  }
 
可以看到每次当父组件重新渲染时,onClick每次都是新的传进Hello,故此引起Hello组件的渲染,引起不必要的渲染,当然,我们一般情况也不必 在意,但我们可以进行优化。优化如下:
1 const  onClick=useCallback (()=> {},[])
 
实现componentWillReceiverComponent|getDerivedStateFromProps 在初次用 hook 封装组件的时候,遇到了需要使用 getDerivedStateFromProps 场景, 官方给出的建议是保存 state 上次的 props,然后跟更新的 props 做比较。实话实说,实现不怎么优雅
https://react.docschina.org/docs/hooks-faq.html#how-do-i-implement-getderivedstatefromprops 
请看下面代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 import  React , { useState, CSSProperties  } from  "react" ;import  { Modal , Icon , message } from  "antd" ;const  styles : {   [key : string ]: CSSProperties ; } = {   modalStyle : {},   container : {     width : "100%" ,     height : "100%" ,     position : "relative"    },   leftIcon : {     fontSize : 40 ,     position : "absolute" ,     left : 0 ,     top : "50%" ,     marginTop : -20 ,     cursor : "pointer"    },   rightIcon : {     fontSize : 40 ,     position : "absolute" ,     right : 0 ,     top : "50%" ,     marginTop : -20 ,     cursor : "pointer"    },   img : {     width : "100%" ,     height : "auto"    },   pictureDesc : {     fontWeight : "bold" ,     marginBottom : 4 ,     marginTop : 4 ,     textAlign : "center" ,     display : "block"    } };interface  PictureScrollViewProps  {   visible : boolean ;   picIndex?: number ;   close : () =>  void ;   data : Array <{     type_name : string ;     url : string ;   }>; }const  PictureScrollView : React .FC <PictureScrollViewProps > = ({    visible,   close,   data,   picIndex = 0  } ) =>  {   const  [currentIndex, setCurrentIndex] = useState (picIndex);      let  [prevIndex, setPreIndex] = useState < number  > 0 ;   if  (picIndex !== prevIndex) {     setPreIndex (picIndex);     setCurrentIndex (picIndex);   }   const  last  = ( ) => {     if  (currentIndex === 0 ) {       message.warn ("已到第一张图片" );     } else  {       setCurrentIndex (currentIndex - 1 );     }   };   const  next  = ( ) => {     if  (currentIndex === data.length  - 1 ) {       message.warn ("已到最后一张图片" );     } else  {       setCurrentIndex (currentIndex + 1 );     }   };   return  (     <Modal        visible ={visible}        footer ={null}        title ={null}        onCancel ={()  =>  {        setCurrentIndex(picIndex);         close();       }}       width={600}     >       {data.length !== 0 ? (         <div  style ={styles.container} >            <picture >              <figcaption  style ={styles.pictureDesc} >                {data[currentIndex].type_name}             </figcaption >              <img  src ={data[currentIndex].url}  alt ="xxx"  style ={styles.img}  />            </picture >            <Icon               type ="left-circle"              theme ="filled"              style ={styles.leftIcon}              onClick ={last}            />           <Icon               type ="right-circle"              theme ="filled"              style ={styles.rightIcon}              onClick ={next}            />         </div >        ) : (         <div > 无图片数据</div >        )}     </Modal >     ); };export  default  PictureScrollView ;
 
上面的组件封装的是一个照片轮播墙,picIndex 是指当前的照片是哪一张,组件初入挂载, picIndex 从组件外传进来,关闭,再次点击另一张照片,picIndex 要相应改变,故此要监听 picIndex prop 的变量,从而同步更新内部的 picIndex state .