最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • React hooks 深度使用总结

    正文概述 掘金(前端钢铁侠)   2021-03-07   955

    这半年来重度使用了react,有的项目中完全使用了hooks,还记得使用react从刚开始的懵懵懂懂,跌跌撞撞,到现在的游刃有余,一路走来真是觉得万分煎熬啊,因为我以前工作中更多的是用vue,有vue的使用经验,所以拾起react也没那么难,但也没并不轻松。

    工作中,有的项目react版本较低,只能使用class组件,当我习惯了写hooks,切换到使用class组件的项目中时,总是觉得很难受,感觉写起来很繁琐,啰嗦,因为总是要写this,this,this,this.state,this.props,还有很多个生命周期方法,还有让我很痛苦的是当我变更状态使用setState时,state是个对象的时候,我还得复制一份这个对象,生成新的对象,再setState。

    现在,只要是在支持hooks的项目中,我都用hooks来写组件,它解决了我以上的所有痛点,让开发组件的体验焕然一新,在一些简单的项目中我发现竟然用两个hooks api就完全足够了,比如useState和useEffect,真是太神奇了!

    好了,现在进入主题吧。

    useState

    一个鲜活的应用程序都有大量状态,内容无法变化的话,我们是无法使用的,所以useState在react中是非常重要的。

    更多介绍可以看官方文档哈,下面来看看它的一个有趣应用。

    实现组件的强制刷新。

    function App() {
    //使用useForceUpdate
    const forceUpdate = useForceUpdate()
    
      return (
        <div>
          <div>Time: {Date.now()}</div>
          <button onClick={forceUpdate}>强制更新</button>
        </div>
      )
    }
    
    const useForceUpdate = () => {
      const [, setState] = useState({})
    
      return () => setState({})
    }
    

    我们可以发现每次点击强制更新button的时候,time的内容也跟着变化。

    useEffect

    每当组件渲染完成时,会调用这个effect,那么我们可以在这里做数据获取、操作DOM和BOM等工作,你还可以返回一个函数,这个函数会在组件卸载前被调用。

    function App() {
      const [count, setCount] = useState(0)
    
      const handleClick = () => {
        setCount(count + 1)
      }
    
      useEffect(() => {
        console.log('组件已挂载')
    
        return () => {
          //可以在这做一些组件的清除工作
          console.log('组件已卸载')
        }
      })
    
      return (
        <div>
          <button onClick={handleClick}>Increment</button>
        </div>
      )
    }
    
    //首次渲染和点击2次Increment按钮,控制台依次打印:
    //"组件已挂载"
    //"组件已卸载"
    //"组件已挂载"
    //"组件已卸载"
    //"组件已挂载"
    

    由此发现,组件挂载完成时,会调用useEffect,当点击Increment按钮,组件的state发生变更时,组件需要重新渲染,然后组件经历了被卸载和被挂载的过程。

    useEffect如何只在组件挂载时执行

    很简单,useEffect的第2个参数是个依赖数组,当我们指定了依赖数组,就只会在依赖发生改变时执行useEffect,它还可以接收一个空数组,这样就只会在组件挂载时执行了。

    useEffect(() => {
        console.log('管你state如何变,我永远只会在组件挂载时执行一次')
    }, [])
    

    useRef和useEffect结合忽略首次渲染(执行)

    useRef不仅仅可以获取dom,它还可以存储任何值,而不随状态改变导致组件重新渲染而改变。

    const isMounted = useRef(false)
    
    useEffect(() => {
      if (!isMounted.current) {
        isMounted.current = true
      } else {
        //do something
      }
    })
    

    useCallback

    useCallback 返回一个经过缓存的回调函数 , 它接收2个参数,一个是回调函数,一个是依赖数据,当依赖项变化的时候,才会重新更新回调函数。它主要是用来做性能优化的。

    比如下面的例子,假如我们的useForceUpdate经常被使用的话,可以使用useCallback包裹,这样每次调用和组件重渲染使用的都是缓存过的函数,减少重新初始化函数的性能损耗。

    function App() {
    
      const forceUpdate = useForceUpdate()
    
      return (
        <div>
          <div>time:{Date.now()}</div>
          <button onClick={forceUpdate}>强制更新</button>
        </div>
      )
    }
    
    const useForceUpdate = () => {
      const [, setState] = useState({})
    
      return useCallback(() => setState({}), [])
    }
    

    useMemo

    useMemo 可以缓存一个值,一般是用来做性能优化的,它接受2个参数,一个是返回计算值的回调函数,一个是依赖数组,当依赖发生变化时,才会重新更新函数,下面来看代码掌握它。

    function App() {
    
      const forceUpdate = useForceUpdate() 
      
      const count = useMemo(() => {
        console.log('called')
        return 1 + 1
      }, [])
    
      return (
        <>
          <div>count:{count}</div>
          <button onClick={forceUpdate}>强制更新</button>
        </>
      )
    }
    

    运行程序首次打印called,当我们点击强制更新button时,控制台没有再次打印called,由此发现,useMemo具有缓存计算的能力,所以在一些耗时的计算中可以使用它。

    useImperativeHandle 和 forwardRef结合

    父组件通过ref访问子组件的时候,可以在子组件中使用useImperativeHandle向父组件暴露接口(实例方法),useImperativeHandle通常和forwardRef结合使用。

    function App() {
      const inputModal = useRef()
    
      const showInputModel = () => {
        inputModal.current.show()
      }
    
      const hideInputModel = () => {
        inputModal.current.hide()
      }
    
      return (
        <div>
          <button onClick={showInputModel}>show modal</button>
          <button onClick={hideInputModel}>hide modal</button>
          <InputModal ref={inputModal} />
        </div>
      )
    }
    
    const InputModal = forwardRef((props, ref) => {
      const inputRef = useRef()
      const [show, setShow] = useState(false)
    
      useImperativeHandle(ref, () => ({
        show: () => setShow(true),
        hide: () => setShow(false),
      }))
    
      useEffect(() => {
        if (show) inputRef.current.focus()
      })
    
      return (
        show && (
          <div>
            <form>
              <div>
                <label>What's your name?</label>
                <input ref={inputRef} />
              </div>
            </form>
          </div>
        )
      )
    })
    
    

    代码中,使用了useImperativeHandle向父组件暴露show和hide方法,这何尝不是实现控制model显示和隐藏的方法?

    useLayoutEffect

    useLayoutEffect 和 useEffect 功能相同,但不同的地方在于渲染机制,useLayoutEffect会跟dom同步渲染,在里面更新dom布局会同步触发重渲染。

    function App() {
      const app = useRef()
    
      // useEffect(() => {
      //   app.current.style.left = '100px'
      // })
    
      useLayoutEffect(() => {
        app.current.style.left = '100px'
      })
    
      return (
        <div
          ref={app}
          style={{
            position: 'absolute',
            width: '80px',
            height: '80px',
            backgroundColor: 'tomato',
          }}
        />
      )
    }
    

    运行上面代码,不断刷新浏览器你可以发现useEffect里的色块你能看到它的布局过程,但在useLayoutEffect中是看不到的,当你遇到这种情况的时候,可以尝试用它来解决。

    最后:

    上面是我在项目中使用hooks的一些发现和经验,分享给大家,hooks的开发体验非常棒,使用起来简单,轻松,几个hooks即可满足开发需求,极大的降低了开发者的学习成本,大大的提高了开发效率。

    除去吃喝拉撒睡,可见我使用react和hooks的时间也不算太长,如有错误的地方,欢迎留言与我交流。


    起源地下载网 » React hooks 深度使用总结

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元