<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          React Hooks 性能優(yōu)化的正確姿勢(shì)

          共 4081字,需瀏覽 9分鐘

           ·

          2021-10-30 02:59

          前言

          React Hooks?出來(lái)很長(zhǎng)一段時(shí)間了,相信有不少的朋友已經(jīng)深度使用了。無(wú)論是?React?本身,還是其生態(tài)中,都在摸索著進(jìn)步。鑒于我使用的?React?的經(jīng)驗(yàn),給大家分享一下。對(duì)于?React hooks,性能優(yōu)化可以從以下幾個(gè)方面著手考慮。

          場(chǎng)景1

          在使用了?React Hooks?后,很多人都會(huì)抱怨渲染的次數(shù)變多了。沒(méi)錯(cuò),官方就是這么推薦的:

          我們推薦把?state?切分成多個(gè)?state?變量,每個(gè)變量包含的不同值會(huì)在同時(shí)發(fā)生變化。

          function Box() {  const [position, setPosition] = useState({ left: 0, top: 0 });  const [size, setSize] = useState({ width: 100, height: 100 });  // ...}

          這種寫(xiě)法在異步的條件下,比如調(diào)用接口返回后,同時(shí)?setPosition?和?setSize,相較于 class 寫(xiě)法會(huì)額外多出一次?render。這也就是渲染次數(shù)變多的根本原因。當(dāng)然這種寫(xiě)法仍然值得推薦,可讀性和可維護(hù)性更高,能更好的邏輯分離。

          針對(duì)這種場(chǎng)景若出現(xiàn)十幾或幾十個(gè)?useState?的時(shí)候,可讀性就會(huì)變差,這個(gè)時(shí)候就需要相關(guān)性的組件化了。以邏輯為導(dǎo)向,抽離在不同的文件中,借助?React.memo?來(lái)屏蔽其他?state?導(dǎo)致的?rerender

          const Position = React.memo(({ position }: PositionProps) => {  // position 相關(guān)邏輯  return (    
          {position.left}
          );});

          因此在?React hooks?組件中盡量不要寫(xiě)流水線代碼,保持在 200 行左右最佳,通過(guò)組件化降低耦合和復(fù)雜度,還能優(yōu)化一定的性能。

          場(chǎng)景2

          class?對(duì)比?hooks,上代碼:

          class Counter extends React.Component {  state = {    count: 0,  };  increment = () => {    this.setState((prev) => ({      count: prev.count + 1,    }));  };  render() {    const { count } = this.state;    return ;  }}
          function Counter() {  const [count, setCount] = React.useState(0);  function increment() {    setCount((n) => n + 1);  }  return ;}

          憑直觀感受,你是否會(huì)覺(jué)得?hooks?等同于?class?的寫(xiě)法?錯(cuò),hooks?的寫(xiě)法已經(jīng)埋了一個(gè)坑。在?count?狀態(tài)更新的時(shí)候,?Counter?組件會(huì)重新執(zhí)行,這個(gè)時(shí)候會(huì)重新創(chuàng)建一個(gè)新的函數(shù)?increment。這樣傳遞給?ChildComponent?的?onClick?每次都是一個(gè)新的函數(shù),從而導(dǎo)致?ChildComponent?組件的?React.memo?失效。

          解決辦法:

          function usePersistFn any>(fn: T) {  const ref = React.useRef(() => {    throw new Error('Cannot call function while rendering.');  });  ref.current = fn;  return React.useCallback(ref.current as T, [ref]);}
          // 建議使用 `usePersistFn`const increment = usePersistFn(() => {  setCount((n) => n + 1);});// 或者使用 useCallbackconst increment = React.useCallback(() => {  setCount((n) => n + 1);}, []);

          上面聲明了?usePersistFn?自定義?hook,可以保證函數(shù)地址在本組件中永遠(yuǎn)不會(huì)變化。完美解決?useCallback?依賴(lài)值變化而重新生成新函數(shù)的問(wèn)題,邏輯量大的組件強(qiáng)烈建議使用。

          不僅僅是函數(shù),比如每次?render?所創(chuàng)建的新對(duì)象,傳遞給子組件都會(huì)有此類(lèi)問(wèn)題。盡量不在組件的參數(shù)上傳遞因?render?而創(chuàng)建的對(duì)象,比如?style={{ width: 0 }}?此類(lèi)的代碼用?React.useMemo?或?React.memo?編寫(xiě)?equal?函數(shù)來(lái)優(yōu)化。

          style?若不需改變,可以提取到組件外面聲明。盡管這樣做寫(xiě)法感覺(jué)太繁瑣,但是不依賴(lài)?React.memo?重新實(shí)現(xiàn)的情況下,是優(yōu)化性能的有效手段。

          const style: React.CSSProperties = { width: 100 };function CustomComponent() {  return ;}

          場(chǎng)景3

          對(duì)于復(fù)雜的場(chǎng)景,使用?useWhyDidYouUpdate?hook 來(lái)調(diào)試當(dāng)前的可變變量引起的?rerender。這個(gè)函數(shù)也可直接使用?ahooks?中的實(shí)現(xiàn)。

          function useWhyDidYouUpdate(name, props) {  const previousProps = useRef();  useEffect(() => {    if (previousProps.current) {      const allKeys = Object.keys({ ...previousProps.current, ...props });      const changesObj = {};      allKeys.forEach(key => {        if (previousProps.current[key] !== props[key]) {          changesObj[key] = {            from: previousProps.current[key],            to: props[key]          };        }      });      if (Object.keys(changesObj).length) {        console.log('[why-did-you-update]', name, changesObj);      }    }    previousProps.current = props;  });}const Counter = React.memo(props => {  useWhyDidYouUpdate('Counter', props);  return 
          {props.count}
          ;
          });

          當(dāng)?useWhyDidYouUpdate?中所監(jiān)聽(tīng)的 props 發(fā)生了變化,則會(huì)打印對(duì)應(yīng)的值對(duì)比,是調(diào)試中的神器,極力推薦。

          場(chǎng)景4

          借助 Chrome Performance 代碼進(jìn)行調(diào)試,錄制一段操作,在?Timings?選項(xiàng)卡中分析耗時(shí)最長(zhǎng)邏輯在什么地方,會(huì)展現(xiàn)出組件的層級(jí)棧,然后精準(zhǔn)優(yōu)化。

          場(chǎng)景5

          在?React?中是極力推薦函數(shù)式編程,可以讓數(shù)據(jù)不可變性作為我們優(yōu)化的手段。我在?React?class 時(shí)代大量使用了?immutable.js?結(jié)合?redux?來(lái)搭建業(yè)務(wù),與?React?中?PureComponnet?完美配合,性能保持非常好。但是在?React hooks?中再結(jié)合?typescript?它就顯得有點(diǎn)格格不入了,類(lèi)型支持得不是很完美。這里可以嘗試一下?immer.js,引入成本小,寫(xiě)法也簡(jiǎn)潔了不少。

          const nextState = produce(currentState, (draft) => {  draft.p.x.push(2);}) // truecurrentState === nextState;

          場(chǎng)景6

          復(fù)雜場(chǎng)景使用?Map?對(duì)象代替數(shù)組操作,map.get(),?map.has(),與數(shù)組查找相比尤其高效。

          // Mapconst map = new Map([['a', { id: 'a' }], ['b', { id: 'b' }], ['c', { id: 'c' }]]);// 查找值map.has('a');// 獲取值map.get('a');// 遍歷map.forEach(n => n);// 它可以很容易轉(zhuǎn)換為數(shù)組Array.from(map.values());// 數(shù)組const list = [{ id: 'a' }, { id: 'b' }, { id: 'c' }];// 查找值list.some(n => n.id === 'a');// 獲取值list.find(n => n.id === 'a');// 遍歷list.forEach(n => n);

          結(jié)語(yǔ)

          React 性能調(diào)優(yōu),除了阻止?rerender,還有與寫(xiě)代碼的方式有關(guān)系。最后,我要推一下近期寫(xiě)的?React?狀態(tài)管理庫(kù) https://github.com/MinJieLiu/heo,也可以作為性能優(yōu)化的一個(gè)手段,希望大家從?redux?的繁瑣中解放出來(lái),省下的時(shí)間用來(lái)享受生活??

          瀏覽 81
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  大鸡巴狂干小骚比视频 | 人人看人人摸人人搞 | 在线韩国精品三级中文hd无码精品 | 美女被内射 | 青青青狠狠 |