最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解如何在React中優(yōu)雅的使用addEventListener

 更新時間:2023年01月31日 10:25:51   作者:uccs  
這篇文章主要為大家詳細介紹了如何在React中優(yōu)雅的使用addEventListener,文中的示例代碼簡潔易懂,對大家學習React有一定的幫助,需要的可以參考一下

在 React Hooks 中使用第三方庫的事件時,很多人會寫成這樣(指的就是我):

const [count, setCount] = useState(0);
useEffect(() => {
  const library = new Library();
  library.on("click", () => {
    console.log(count); // 拿不到最新的 count
  });
}, []);

這樣寫會有問題:

它只會在這個組件加載時,綁定事件,如果這個事件中用到了其他的 state,那么這個狀態(tài)發(fā)生變化時事件中是拿不到最新的 state

你會想到,我把 state 放到依賴項中:

const [count, setCount] = useState(0);
useEffect(() => {
  const library = new Library();
  // click 事件會重復綁定
  library.on("click", () => {
    console.log(count);
  });
}, [count]);

這樣做又會有新問題:click 事件會重復綁定

這時候你說那我先卸載 click 事件,在綁定事件:

const [count, setCount] = useState(0);
useEffect(() => {
  const library = new Library();
  library.on("click", handleClick);
  return () => {
    // 卸載不掉事件,還是會重復綁定
    handleClick && library.un("click", handleClick);
  };
}, [count]);

const handleClick = () => {
  console.log(count);
};

你驚奇的發(fā)現(xiàn),居然卸載不掉之前的事件,還是會重復綁定事件。

如何解決這個問題呢?

使用 addEventListener 代替第三方庫的事件

這里使用 addEventListener 代替第三方庫的事件,初始代碼

const Test = (props) => {
  const ref = useRef();
  const [count, setCount] = useState(0);

  useEffect(() => {
    const handleClick = (event) => {
      console.log("clicked");
      console.log("count", count);
    };
    const element = ref.current;
    element.addEventListener("click", handleClick);
    return () => {
      element.removeEventListener("click", handleClick);
    };
  }, []);

  const onClickIncrement = () => {
    setCount(count + 1);
  };
  return (
    <>
      <h2>Test</h2>
      <button onClick={onClickIncrement}>點擊 +1</button>
      <div>count: {count}</div>
      <button ref={ref}>Click Test Button</button>
    </>
  );
};

方法一:state 變化,卸載/綁定事件

將 state 放在依賴項中,就要解決 state 變化時,事件重復綁定的問題

解決事件重復綁定問題,首先想到的是事件卸載

你很容易就會想到這樣寫

useEffect(() => {
  handleClick && ref.current.removeEventListener("click", handleClick);
  ref.current.addEventListener("click", handleClick);
}, [count]);

const handleClick = () => {
  console.log(count);
};

這在 React Hooks 中是一個坑,state 變化后會 handleClick 事件函數(shù)會重新聲明,新的 handleClick 和之前的 handleClick 不是一個事件函數(shù),導致 removeEventListener 移除的事件函數(shù)不是之前的事件函數(shù)

那你又會想到,我給 handleClick 加個 useCallback

useEffect(() => {
  handleClick && ref.current.removeEventListener("click", handleClick);
  ref.current.addEventListener("click", handleClick);
}, [count]);

const handleClick = useCallback(() => {
  console.log(count);
}, []);

這樣寫的話還是會有同一個問題:依賴項為空數(shù)組,就拿不到最新的 state;依賴項中放入 state,state 變化后就不是同一個事件函數(shù)了,無法移除事件

如何解決這個問題呢?

把事件函數(shù)保存為狀態(tài):

  • 當 count 變化時,掛載事件,同時將事件函數(shù)保存為 state
  • 當 eventFn.fn 變化時,在 useEffect return 中卸載之前的事件函數(shù)(這里利用的是閉包)

具體的代碼:

const Test = () => {
  const ref = useRef();
  const [count, setCount] = useState(0);
  const [eventFn, setEventFn] = useState({ fn: null });

  useEffect(() => {
    mountEvent();
  }, [count]);

  const mountEvent = () => {
    if (!ref.current) return;
    //  eventFn.fn && ref.current.removeEventListener("click", eventFn.fn);  // 下面看不懂的話,也可以這樣寫
    ref.current.addEventListener("click", handleClick);
    setEventFn({ fn: handleClick });
  };

  useEffect(() => {
    return () => {
      eventFn.fn && ref.current.removeEventListener("click", eventFn.fn); // 這里用的是閉包,和上面注釋部分任選其一
    };
  }, [eventFn.fn]);

  const handleClick = () => {
    console.log(count);
  };

  const onClickIncrement = () => {
    setCount(count + 1);
  };

  return (
    <>
      <h2>Test</h2>
      <button onClick={onClickIncrement}>點擊 +1</button>
      <div>count: {count}</div>
      <button ref={ref}>Click Test Button</button>
    </>
  );
};

方法二:使用閉包的方式卸載事件

利用閉包,可以將方法一簡化

const Test = () => {
  const ref = useRef();
  const [count, setCount] = useState(0);

  useEffect(() => {
    const element = ref.current;
    element.addEventListener("click", handleClick);
    return () => {
      element.removeEventListener("click", handleClick);
    };
  }, [count]);

  const handleClick = () => {
    console.log(count);
  };

  const onClickIncrement = () => {
    setCount(count + 1);
  };

  return (
    <>
      <h2>Test</h2>
      <button onClick={onClickIncrement}>點擊 +1</button>
      <div>count: {count}</div>
      <button ref={ref}>Click Test Button</button>
    </>
  );
};

useEffect return 中的變量用的是閉包,這點剛開始學的時候不好理解

方法三:使用 ref 保存狀態(tài)

ref 保存的數(shù)據(jù)雖然不能用于頁面渲染,但可以作為 state 備份,在 state 變化時更新 ref

在事件函數(shù)中就能拿到最新的 stateRef

const Test = () => {
  const ref = useRef();
  const [count, setCount] = useState(0);

  const countRef = useRef(count);
  useEffect(() => {
    countRef.current = count;
  }, [count]);

  useEffect(() => {
    const element = ref.current;
    element.addEventListener("click", handleClick);
  }, []);

  const handleClick = () => {
    console.log(countRef.current);
  };

  const onClickIncrement = () => {
    setCount(count + 1);
  };

  return (
    <>
      <h2>Test</h2>
      <button onClick={onClickIncrement}>點擊 +1</button>
      <div>count: {count}</div>
      <button ref={ref}>Click Test Button</button>
    </>
  );
};

優(yōu)化 state 手動維護

上面三種方法,都有個問題,state 需要手動維護

這一步如何優(yōu)化呢?

方法一和方法二,優(yōu)化的方式都一樣:將依賴項是 count 改為 state

const [state, setState] = useState({ count: 0 });

useEffect(() => {
  // ...
}, [state]);

方法三的優(yōu)化是,用 stateRef 保存 ref 對象,當 state 變化時,遍歷 state 給 stateRef 賦值

事件函數(shù)中使用 stateRef

const [state, setState] = useState({ count: 0 });
const stateRef = useRef({});
useEffect(() => {
  Object.keys(state).forEach((key) => {
    stateRef.current[key] = state[key];
  });
}, [state]);

到此這篇關于詳解如何在React中優(yōu)雅的使用addEventListener的文章就介紹到這了,更多相關React addEventListener內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • ReactNative?狀態(tài)管理redux使用詳解

    ReactNative?狀態(tài)管理redux使用詳解

    這篇文章主要介紹了ReactNative?狀態(tài)管理redux使用詳解
    2023-03-03
  • react中如何對自己的組件使用setFieldsValue

    react中如何對自己的組件使用setFieldsValue

    react中如何對自己的組件使用setFieldsValue問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • react父組件更改props子組件無法刷新原因及解決方法

    react父組件更改props子組件無法刷新原因及解決方法

    使用過vue的朋友都知道,vue父組件更改props的值,子組件是會刷新的,而react就未必,今天通過一個例子給大家介紹react父組件更改props子組件無法刷新原因,需要的朋友可以參考下
    2022-09-09
  • React組件化學習入門教程講解

    React組件化學習入門教程講解

    React是現(xiàn)在前端使用頻率最高的三大框架之一,React率先提出虛擬DOM的思想和實現(xiàn),使其保持有良好的性能。本篇文章將對React組件化的入門學習進行講解,同時針對模塊化的思想進行概述,為接下來組件化開發(fā)的文章進行知識儲備
    2022-09-09
  • 淺談React Native 中組件的生命周期

    淺談React Native 中組件的生命周期

    本篇文章主要介紹了淺談React Native 中組件的生命周期,非常具有實用價值,需要的朋友可以參考下
    2017-09-09
  • 如何使用Next.js?+?Prisma?+?MySQL開發(fā)全棧項目

    如何使用Next.js?+?Prisma?+?MySQL開發(fā)全棧項目

    在Next.js項目的任何地方都可以使用Prisma來訪問數(shù)據(jù)庫,Prisma提供了豐富的查詢方法,滿足您在項目中的各種需求,這篇文章主要介紹了如何使用Next.js+Prisma+MySQL開發(fā)全棧項目的相關資料,需要的朋友可以參考下
    2026-03-03
  • 詳解React中的todo-list

    詳解React中的todo-list

    這篇文章主要介紹了React中的todo-list的相關知識,非常不錯,具有一定的參考借鑒價值,需要的朋友參考下吧
    2018-07-07
  • 淺談react受控組件與非受控組件(小結)

    淺談react受控組件與非受控組件(小結)

    本篇文章主要介紹了淺談react受控組件與非受控組件(小結),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • react 通過后端接口實現(xiàn)路由授權的示例代碼

    react 通過后端接口實現(xiàn)路由授權的示例代碼

    本文主要介紹了React應用中通過后端接口獲取路由授權,實現(xiàn)動態(tài)和靈活的權限管理,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-11-11
  • 在React中正確處理異步操作的方法

    在React中正確處理異步操作的方法

    本文全面介紹了在React中處理異步操作的方法、最佳實踐及常見坑點,涵蓋數(shù)據(jù)獲取、延時任務、用戶交互、動畫和效果等典型場景,并提供了如useEffect、AbortController、ReactQuery等具體實現(xiàn)示例,感興趣的朋友一起看看吧
    2025-03-03

最新評論

缙云县| 长沙县| 安西县| 青冈县| 同德县| 西和县| 绥中县| 西峡县| 北海市| 博白县| 奉新县| 洛宁县| 凤台县| 英山县| 万州区| 禄丰县| 文昌市| 东乡县| 元朗区| 鹤山市| 潢川县| 赤峰市| 青川县| 凌海市| 吐鲁番市| 岱山县| 渭源县| 固始县| 平凉市| 蒙山县| 定州市| 婺源县| 洪泽县| 工布江达县| 滦南县| 濮阳县| 色达县| 通榆县| 钦州市| 乌恰县| 陵川县|