react hooks的使用记录

"对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 (
{ number }
)

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 (
    <>
      
{num}
)

image.png
数组中可以放多个useState的值,每个值发生变化都会触发,实际开发中,这个依赖项数组只放一个变量。第二个参数一般情况下不要使用引用类型,因为比对的是浅比较,引用类型的指针地址没有变化的话,进入不到useEffect中。
useEffect第一个effect函数参数中还可以返回一个函数,表示解绑副作用,比如在effect函数中有个定时器,在组件销毁时需要清除定时器,此时要解绑,就可以在effect函数中返回一个函数,这个函数相当于componentWillUnmount生命周期。在使用中,重新渲染依赖项,也会先执行解绑副作用,在进行副作用,即effect函数。

  const [num, setNum] = useState(1)
  useEffect(() => {
    console.log('componentDidUpdate')
    return ()=>{
      console.log('componentWillUnmount')
    }
  }, [num])
  return (
    <>
      
{num}
)

image.png


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 (
    
      

{name}

{price}

普通的name:{getProductName()}

memo化的:{memo_getProductName()}

) }

useMemo也可以包裹标签与子组件

/* 用 useMemo包裹的list可以限定当且仅当list改变的时候才更新此list,这样就可以避免selectList重新循环 */
 {useMemo(() => (
      
{ selectList.map((i, v) => ( {i.patentName} ))}
), [selectList])}
/* 只有当props中,list列表改变的时候,子组件才渲染 */
const  goodListChild = useMemo(()=>  ,[ props.list ])

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

/* 用react.memo */
const DemoChildren = React.memo((props)=>{
   /* 只有初始化的时候打印了 子组件更新 */
    console.log('子组件更新')
   useEffect(()=>{
       props.getInfo('子组件')
   },[])
   return 
子组件
}) const DemoUseCallback=({ id })=>{ const [number, setNumber] = useState(1) /* 此时usecallback的第一参数 (sonName)=>{ console.log(sonName) } 经过处理赋值给 getInfo */ const getInfo = useCallback((sonName)=>{ console.log(sonName) },[id]) return
{/* 点击按钮触发父组件更新 ,但是子组件没有更新 */}
}

你可能感兴趣的