hooks學習筆記—hooks的典型案例

清除 effect

通常,組件卸載時需要清除 effect 創建的諸如訂閱或計時器 ID 等資源。要實現這一點,useEffect 函數需返回一個清除函數。也就是說,要想在組件銷燬的時候搞一些事情,需要useEffect 末尾返回一個函數,在這個函數裏面可以寫具體銷燬的內容。

看下面的例子,在當前頁面裏面,頁面的標題是'測試title',當切換到其他頁面時,頁面的標題變成‘前端精讀’

import React, { useEffect } from 'react';

function useDocumentTitle(title) {
  useEffect(() => {
    document.title = title;
    return () => {
      console.log('銷燬1————————————————');
      document.title = '前端精讀';
    };
  }, [title]);
}

export default function CheckboxDemo() {
  useDocumentTitle('測試title');

  return <div />;
}

監聽頁面大小變化,網絡是否斷開

效果:在組件調用 useWindowSize 時,可以拿到頁面大小,並且在瀏覽器縮放時自動觸發組件更新。

import React, { useEffect, useState } from 'react';

function getSize() {
  return {
    innerHeight: window.innerHeight,
    innerWidth: window.innerWidth,
    outerHeight: window.outerHeight,
    outerWidth: window.outerWidth,
  };
}

function useWindowSize() {
  const [windowSize, setWindowSize] = useState(getSize());

  function handleResize() {
    setWindowSize(getSize());
  }

  useEffect(() => {
    window.addEventListener('resize', handleResize);

    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, []);
  return windowSize;
}

export default function Demo() {
  const windowSize = useWindowSize();
  return <div>頁面寬度{windowSize.innerWidth}</div>;
}

動態注入 css

效果:在頁面注入一段 class,並且當組件銷燬時,移除這個 class。

const className = useCss({
  color: "red"
});

return <div className={className}>Text.</div>;

實現:可以看到,Hooks 方便的地方是在組件銷燬時移除副作用,所以我們可以安心的利用 Hooks 做一些副作用。注入 css 自然不必說了,而銷燬 css 只要找到注入的那段引用進行銷燬即可,具體可以看這個 代碼片段

DOM 副作用修改 / 監聽場景有一些現成的庫了,從名字上就能看出來用法:document-visibilitynetwork-statusonline-statuswindow-scroll-positionwindow-sizedocument-title

組件輔助

Hooks 還可以增強組件能力,比如拿到並監聽組件運行時寬高等。

獲取組件寬高

效果:通過調用 useComponentSize 拿到某個組件 ref 實例的寬高,並且在寬高變化時,rerender 並拿到最新的寬高。

import React, { useLayoutEffect, useState, useRef } from 'react';

function getSize(el) {
  if (!el) {
    return {};
  }

  return {
    width: el.offsetWidth,
    height: el.offsetHeight,
  };
}

function useComponentSize(ref) {
  const [ComponentSize, setComponentSize] = useState(getSize(ref.current));

  function handleResize() {
    if (ref && ref.current) {
      setComponentSize(getSize(ref.current));
    }
  }

  useLayoutEffect(() => {
    handleResize();

    let resizeObserver = new ResizeObserver(() => handleResize());
    resizeObserver.observe(ref.current);

    return () => {
      resizeObserver.disconnect(ref.current);
      resizeObserver = null;
    };
  }, []);
  return ComponentSize;
}

export default function Demo() {
  const ref = useRef(null);
  const componentSize = useComponentSize(ref);
  return (
    <>
      {componentSize.width}
      <textarea ref={ref} />
    </>
  );
}

拿到組件 onChange 拋出的值 

效果:通過 useInputValue() 拿到 Input 框當前用戶輸入的值,而不是手動監聽 onChange 再騰一個 otherInputValue 和一個回調函數把這一堆邏輯寫在無關的地方。

import React, { useState, useCallback } from 'react';

function useInputValue(initialValue) {
  const [value, setValue] = useState(initialValue);
  const onChange = useCallback(function(e) {
    setValue(e.currentTarget.value);
  }, []);
  return {
    value,
    onChange,
  };
}

export default function Demo() {
  const name = useInputValue('jjsun');
  return (
    <>
      {name.value}
      <input {...name} />
    </>
  );
}

暫時寫這麼多吧,其他看這篇文章吧!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章