乐趣区

关于前端:使用hooks的一些小感想

这里文章说的都是 hooksreact

那什么是 hooks

故名思义 Hooks 译为钩子,Hooks 就是在函数组件内,负责钩进内部性能的函数。

(说了又如同没说)

有什么爽的👌

  • 函数组件原地飞升
  • 不必管 this 了
  • 生命周期也不必记那么多了

开始完结的生命周期能够写在一起,代码更丑陋了

useEffect(()=>{console.log('开波')
  return ()=>{console.log('完结')
  }
},[])
// ps. 空数组就是只进入一次

props 的值的变动,xx 值的变动都能放在一起监听

useEffect(()=>{console.log('无论是数组还是对象,数据多深都能进(起初才发现也不是多深都能啦),这不比 vue 的 watch 爽?')
  // 那么 useEffect 是怎么监听数据变动的呢
  // 它和 useLayoutEffect 又有什么区别呢
  // 这要从 hooks 的根底概念链表说起,请往下看
},[props.a,b])

通过看 useEffect 的源码,咱们不难发现

// 通过看源码咱们得悉

 for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {if (is(nextDeps[i], prevDeps[i])) {continue;}
    return false;
  }
// 咱们晓得它的比照办法是
// 其中外面的 is 是这个
import is from 'shared/objectIs';
function is(x: any, y: any) {
  return ((x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare
  );
}

const objectIs: (x: any, y: any) => boolean =
  typeof Object.is === 'function' ? Object.is : is;

export default objectIs;

所以其实它就是用 Object.is 做比拟

有须要做深比拟的能够用 ahooksuseDeepCompareEffect,用法与 useEffect 统一,但 deps 通过 lodash 的 isEqual 进行深比拟。

  • 代码复用更高

吐槽一下

闭包陷阱

import {useEffect, useState} from 'react'

export default function App() {const [count, setCount] = useState(0)
  useEffect(()=>{setInterval(() => {setCount(count + 1)
    }, 1000);
  }, [])
  return (<p>count={count}</p>
  );
}

大家可能会始终期待着数字的变动,但它就偏不,始终放弃着 1

事件为什么会倒退成这样,那就要从底层的渲染开始说起

首次渲染 -> 执行 APP->usestate 设置 count 为初始 0 ->1 秒后 state 扭转 -> 视图更新 -> 依照 fiber 链表执行 hooks->useEffect deps 不变 -> 而后 1 秒后的 count 始终都是 0 +1

解决办法:

// 有仔细的网友可能会发现,网上其余中央可能会倡议在 useEffect 的 deps 上加上 count
useEffect(()=>{setInterval(() => {setCount(count + 1)
  }, 1000);
}, [count])
// 这样的确能拿到最新的 count
// ❌然而这里喔不倡议这样写
// 因为你想想,每次 count 的更新它都会从新进去建一个新的定时器
// 当前画面就会很鬼畜

倡议版本办法

useEffect(()=>{setInterval(() => {setCount(res=>(res+1))
  }, 1000);
}, [])
// setCount 自身能够传办法,原本就是最新的值

高级版本 ref 大法

// 简略来说就是利用 useRef 返回的是同一个对象,指向同一片内存
let ref_ = useRef(1)
ref_.current++
useEffect(()=>{setInterval(()=>{console.log(ref.current) // 3
  }, 1000)
})

不能用判断或者随机函数

举个🌰

if (Math.random() > 0.5) {useState('first')
} 
let showSex = true
if(showSex){const [ sex, setSex] = useState('男');
    showSex = false;
}

以上的行为都是打咩的

起因是 hooks 的数据管理是用链表治理的,所以数据不能一时有一时没

举个不太失当的例子,就像

  • 数组 [0] 代表 useState(‘A’)
  • 数组 [1] 代表 useState(‘B)
  • 当初你忽然把 ’A’ 删掉了,那就变成数组 [0] 代表 useState(‘B’)了
  • 那么你就不是你了,他也不是他了

useCallBack 还是 useMemo

仅仅 依赖数据 发生变化, 才会从新计算结果,说是为了性能优化,起到缓存的作用,

这里说一个面试常问的useCallBackuseMemo 有什么区别?

网上各种解析简明扼要的,一句话其实就是

useCallback 缓存钩子函数,useMemo 缓存返回值(计算结果)[当然 useMemo 也能够传入函数]。

这个时候,有好奇宝贝就会问了, 那用这个会多那么多代码量,有什么用呢

答案是:性能优化,这里就要波及到更深层的 react 的渲染原理了,” 比拟更新!!”,react 每次渲染的时候,它都把值和函数从新计算渲染,这里就会耗费点内存了,用上那 2 玩意,其实就是通知 react,咱们没有变动,帮我存起来,不必再比拟了

那么有些姓杠的小朋友,这时候就不耐烦了,站起来问道:为什么 react 不帮咱们主动做这些优化呢,我就想静静地写代码,为什么还要思考该不该包个useCallBack

问得好,这里顺便 @一下官网团队,心愿相干单位能亲密关注这个问题

还会有些害羞的小朋友会嘀咕着,为什么 class 组件的时候就不须要留神这些呢

集体鄙见:新旧版本的渲染办法其实差不多的,我感觉前端深入研究性能优化是没有前途的,框架或者浏览器,一次小小的版本更新,可能成果就远远胜过了你多少个日日夜夜的辛勤付出了。

总结

hooks 需好,但要小心应用


<center> 明天关注公众号,有小哥哥在线领导 </center>

本文由博客一文多发平台 OpenWrite 公布!

退出移动版