前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >hooks的理解

hooks的理解

作者头像
用户4792657
发布2022-07-06 14:13:38
9870
发布2022-07-06 14:13:38
举报
文章被收录于专栏:山海亦有归期山海亦有归期

useState

使用

useState的用法很简单,返回一个数组,数组的值为当前state和更新state的函数;

useState的参数是变量、对象或者是函数,变量或者对象会作为state的初始值,如果是函数,函数的返回值会作为初始值。

批量更新

代码语言:javascript
复制
function Count(){
    let [count,setCount] = useState(0)
    const handleAdd = function(){
        setCount(count+1)
        setCount(count+1)
    }
    return(
        <div>
            <p>{count}</p>    
            /*每次点击加1*/
            <button onClick={handleAdd}>加一</button>
        </div>
    )
}

在同一个事件中并不会因为调用了两次setCount而让count增加两次,试想如果在同一个事件中每次调用setCount都生效,那么每调用一次setCount组件就会重新渲染一次,这无疑使非常影响性能的;实际上如果修改的state是同一个,最后一个setCount函数中的新state会覆盖前面的

useEffect&&useLayoutEffect

相同点

这两个hook用法都一致,都是处理副作用的hook函数。第一个参数是回调函数,第二个参数是个数组。数组的内容是依赖项deps,依赖项改变后执行回调函数;注意组件每次渲染会默认执行一次,如果不传第二个参数,则只要该组件有state(状态)改变就会触发回调函数;如果传一个空数组,则只会在初始化时执行一次。如果在回调函数中return返回了一个函数,则在组件销毁时调用,同时组件每次重新渲染的时候都会先执行该函数再调用回调函数。

区别
  • hook执行时机不同

useLayoutEffect是在页面渲染前执行,是同步调用。

useEffect是在页面渲染后执行,是异步调用。

使用

视情况而定,如果回调函数会修改state导致组件重新渲染,可以使用useLayoutEffect,因为这个时候用useEffect可能会造成页面闪烁;如果回调函数中去请求数据或者执行时间过长,建议使用useEffect;因为这个时候使用useLayoutEffect会造成堵塞浏览器渲染。

memo

React.memoPureComponent作用类似,可以用作性能优化,React.memo 是高阶组件,函数组件和类组件都可以使用, 和区别PureComponentReact.memo只能对props的情况确定是否渲染,而PureComponent是针对propsstate

React.memo 接受两个参数,第一个参数原始组件本身,第二个参数,可以根据一次更新中props是否相同决定原始组件是否重新渲染。是一个返回布尔值,true 证明组件无须重新渲染,false证明组件需要重新渲染,这个和类组件中的shouldComponentUpdate()正好相反 。

React.memo: 第二个参数 返回 true 组件不渲染 , 返回 false 组件重新渲染。 shouldComponentUpdate: 返回 true 组件渲染 , 返回 false 组件不渲染。

接下来我们做一个场景,控制组件在仅此一个props数字变量,一定范围渲染。

例子🌰:

控制 props 中的 number

  • 1 只有 number 更改,组件渲染。
  • 2 只有 number 小于 5 ,组件渲染。
代码语言:javascript
复制
function TextMemo(props){
    console.log('子组件渲染')
    if(props)
    return <div>hello,world</div> 
}

const controlIsRender = (pre,next)=>{
   if(pre.number === next.number  ){ // number 不改变 ,不渲染组件
       return true 
   }else if(pre.number !== next.number && next.number > 5 ) { // number 改变 ,但值大于5 , 不渲染组件
       return true
   }else { // 否则渲染组件
       return false
   }
}

const NewTexMemo = memo(TextMemo,controlIsRender)
class Index extends React.Component{
    constructor(props){
        super(props)
        this.state={
            number:1,
            num:1
        }
    }
    render(){
        const { num , number }  = this.state
        return <div>
            <div>
                改变num:当前值 { num }  
                <button onClick={ ()=>this.setState({ num:num + 1 }) } >num++</button>
                <button onClick={ ()=>this.setState({ num:num - 1 }) } >num--</button>  
            </div>
            <div>
                改变number: 当前值 { number } 
                <button onClick={ ()=>this.setState({ number:number + 1 }) } > number ++</button>
                <button onClick={ ()=>this.setState({ number:number - 1 }) } > number -- </button>  
            </div>
            <NewTexMemo num={ num } number={number}  />
        </div>
    }
}

效果:

memo.gif
memo.gif

memo.gif

完美达到了效果,React.memo一定程度上,可以等价于组件外部使用shouldComponentUpdate ,用于拦截新老props,确定组件是否更新。

useMemo

useMemo接收两个参数,第一个参数是一个函数,返回值用于产生保存值,第二个参数是一个数组,作为dep依赖项。当数组里面的依赖项发生变化,重新执行第一个函数,产生新的值。

应用场景

1.缓存一些值,避免重新执行上下文

代码语言:javascript
复制
const number = useMemo(()=>{
/** 大量的逻辑运算**/
return number
},[props.number])
//只有props的number改变时,重新计算number的值

2 减少不必要的dom循环

代码语言:javascript
复制
/* 用 useMemo包裹的list可以限定当且仅当list改变的时候才更新此list,这样就可以避免selectList重新循环 */
 {useMemo(() => (
      <div>{
          selectList.map((i, v) => (
              <span
                  className={style.listSpan}
                  key={v} >
                  {i.patentName} 
              </span>
          ))}
      </div>
), [selectList])}

3 减少子组件渲染

代码语言:javascript
复制
/* 只有当props中,list列表改变的时候,子组件才渲染 */
const  goodListChild = useMemo(()=> <GoodList list={ props.list } /> ,[ props.list ])

useCallback

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

缓存函数,当页面重新渲染render时,依赖项不变时,不会去重新生成这个函数。

子组件使用React.memo包裹,父组件需要传递至子组件的函数使用useCallback缓存,来避免子组件不必要的重新render。当传给子组件函数时。子组件的memo判断会出问题,传递进去的函数都是重新创建的,引用地址前后不一致。所以当用useCallback去缓存这个函数,则memo判断则不会有问题,会正常缓存

代码语言:javascript
复制
/* 用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>
}

useRef

useRef的作用:

  • 一 是可以用来获取dom元素,或者class组件实例 。
  • 二 创建useRef时候,会创建一个原始对象,只要函数组件不被销毁,原始对象就会一直存在,那么我们可以利用这个特性,来通过useRef保存一些数据。
代码语言:javascript
复制
const DemoUseRef = ()=>{
    const dom= useRef(null)
    const handerSubmit = ()=>{
        /*  <div >表单组件</div>  dom 节点 */
        console.log(dom.current)
    }
    return <div>
        {/* ref 标记当前dom节点 */}
        <div ref={dom} >表单组件</div>
        <button onClick={()=>handerSubmit()} >提交</button> 
    </div>
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-03-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • useState
    • 使用
      • 批量更新
        • 相同点
        • 区别
        • 使用
    • useEffect&&useLayoutEffect
    • memo
    • useMemo
      • 应用场景
      • useCallback
      • useRef
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档