"对react的自带hooks进行的演绎总结"
react-hooks:
常见,useState、useEffect、useMemo、useRef、useCallback、useContext
少见,useReducer、useImperativeHandle、useDebugValue、useTransition、useLayoutEffect

useState
因为函数式组件没有this与state,无奈间接批改state,因而useState是react对外裸露的一个对state操作的钩子函数。
该函数可接管一个参数,是为变量的默认值,如果不写的话,变量默认为undefined
useState返回一个数组,数组的第一位是变量名,第二位是扭转该变量的函数,查看源码,会发现这个函数是一个dispatch函数(异步),所以间接查看该变量失去的是原先的值,如果要查看该变量值,配合应用useEffect去监听。
扭转变量的函数有一个参数,应用的时候,间接放值类型,不可是表达式等。

 const [number, setNumber] = useState(0) /* 0为初始值 */ return (<div>     <span>{ number }</span>     <button onClick={ ()=> {       setNumber(number+1) /* 写法一 */       setNumber(number=>number + 1 ) /* 写法二 */       console.log(number) /* 这里的number是不可能即时扭转的  */     } } >num++</button> </div>)

useEffect
函数式组件也没有生命周期,用useEffect取代生命周期。同时对应前文所讲,useState批改的值,在这里是能够取到的,实现数据的交互。useEffect也叫副作用,顾名思义,是在渲染实现后执行。理论应用中useEffect必须填写第二个参数来应用,否则这可能会导致性能问题,比方两次渲染的数据齐全一样。
第一个参数是effect函数,第二个参数是依赖项,是一个数组,如果是一个空数组,useEffect不依赖于props或state中的任何值,所以它永远都不须要反复执行,该钩子会实现componentDidMount生命周期函数的性能,即页面加载时触发一次。
如果不是空数组,就要增加useState中的变量,这个变量每次发生变化就会触发useEffect,即componentDidUpdate,同时也包含componentDidMount

  const [num, setNum] = useState(1)  useEffect(() => {    console.log('componentDidUpdate')  }, [num])  useEffect(() => {    console.log('componentDidMount')  }, [])  return (    <>      <div>{num}</div>      <button onClick={() => { setNum(num + 1) }}>点击</button>    </>  )


数组中能够放多个useState的值,每个值发生变化都会触发,理论开发中,这个依赖项数组只放一个变量。第二个参数个别状况下不要应用援用类型,因为比对的是浅比拟,援用类型的指针地址没有变动的话,进入不到useEffect中。
useEffect第一个effect函数参数中还能够返回一个函数,示意解绑副作用,比方在effect函数中有个定时器,在组件销毁时须要革除定时器,此时要解绑,就能够在effect函数中返回一个函数,这个函数相当于componentWillUnmount生命周期。在应用中,从新渲染依赖项,也会先执行解绑副作用,在进行副作用,即effect函数。

  const [num, setNum] = useState(1)  useEffect(() => {    console.log('componentDidUpdate')    return ()=>{      console.log('componentWillUnmount')    }  }, [num])  return (    <>      <div>{num}</div>      <button onClick={() => { setNum(num + 1) }}>点击</button>    </>  )


useMemo
与useEffect类似,参数也是一个函数与一个依赖项数组,次要作用是有助于防止在每次渲染时都进行高开销的计算。
它仅会在某个依赖项扭转时才从新计算值,这个过程会在页面渲染时进行,类比生命周期就是shouldComponentUpdate
如果没有提供依赖项数组,useMemo在每次渲染时都会计算新的值。不要在这个函数外部执行与渲染无关的操作,诸如副作用这类的操作属于useEffect的实用领域,而不是useMemo。
useMemo会返回一个memo函数的后果return () => name,用定义的变量去接管并应用该定义的变量。
与useEffect的比拟:
useMemo: 渲染期间管制,值/函数的触发/扭转
useEffect: 渲染完结后管制,值/函数的触发/扭转

// 产品名称列表const nameList = ['apple', 'peer', 'banana', 'lemon']const example = (props) => {  // 产品名称、价格  const [price, setPrice] = useState(0)  const [name, setName] = useState('apple')  function getProductName() {    console.log('getProductName触发')    return name  }    // 只对price响应  useEffect(() => {    console.log('price effect 触发')  }, [price])  // 只对name响应  useEffect(() => {    console.log('name effect 触发')    getProductName()  }, [name])  // memo化的getProductName函数  const memo_getProductName = useMemo(() => {    console.log('name memo 触发')    return () => name  // 返回一个函数  }, [name])  return (    <Fragment>      <p>{name}</p>      <p>{price}</p>      <p>一般的name:{getProductName()}</p>      <p>memo化的:{memo_getProductName()}</p>      <button onClick={() => setPrice(price + 1)}>价格+1</button>      <button onClick={() => setName(nameList[Math.random() * nameList.length << 0])}>批改名字</button>    </Fragment>  )}

useMemo也能够包裹标签与子组件

/* 用 useMemo包裹的list能够限定当且仅当list扭转的时候才更新此list,这样就能够防止selectList从新循环 */ {useMemo(() => (      <div>{          selectList.map((i, v) => (              <span                  className={style.listSpan}                  key={v} >                  {i.patentName}               </span>          ))}      </div>), [selectList])}
/* 只有当props中,list列表扭转的时候,子组件才渲染 */const  goodListChild = useMemo(()=> <GoodList list={ props.list } /> ,[ props.list ])

useCallback
useMemo和useCallback接管的参数都是一样,都是在其依赖项发生变化后才执行,都是返回缓存的值,区别在于useMemo返回的是函数运行的后果,useCallback返回的是函数。返回的callback能够作为props回调函数传递给子组件。

/* 用react.memo */const DemoChildren = React.memo((props)=>{   /* 只有初始化的时候打印了 子组件更新 */    console.log('子组件更新')   useEffect(()=>{       props.getInfo('子组件')   },[])   return <div>子组件</div>})const DemoUseCallback=({ id })=>{    const [number, setNumber] = useState(1)    /* 此时usecallback的第一参数 (sonName)=>{ console.log(sonName) }     通过解决赋值给 getInfo */    const getInfo  = useCallback((sonName)=>{          console.log(sonName)    },[id])    return <div>        {/* 点击按钮触发父组件更新 ,然而子组件没有更新 */}        <button onClick={ ()=>setNumber(number+1) } >减少</button>        <DemoChildren getInfo={getInfo} />    </div>}