簡體   English   中英

如何將它變成 React Hooks for useEffect()?

[英]How do I turn this into React Hooks for useEffect()?

我想用useEffect把它變成反應鈎子,但它一直給我一個錯誤。 當我使用useEffect時,不會添加或刪除 class 名稱。

componentDidMount() {
    window.addEventListener("scroll", () => {
        const isTop = window.scrollY < 100;

        const img = document.getElementById("logo-img");
        const name = document.getElementById("name");

        if (isTop) {
            img.classList.remove("logo-small");
            name.classList.remove("no-display");
        } else {
            img.classList.add("logo-small");
            name.classList.add("no-display");
        }
    });
}

componentWillUnmount() {
    window.removeEventListener("scroll");
}

這就是我將其轉換為反應鈎子useEffect的內容,當我實現此功能時,不會刪除或添加 class 名稱

useEffect(() => {
    window.scrollTo(0, 0);

    window.addEventListener("scroll", () => {
        const isTop = window.scrollY < 100;

        const img = document.getElementById("logo-img");
        const name = document.getElementById("name");

        if (isTop) {
            img.classList.remove("logo-small");
            name.classList.remove("no-display");
        } else {
            img.classList.add("logo-small");
            name.classList.add("no-display");
        }
    });
}, []);

根據文檔,您可以嘗試使用useLayoutEffect

小費

如果您從 class 組件遷移代碼,請注意useLayoutEffect在與componentDidMountcomponentDidUpdate相同的階段觸發。 但是,我們建議首先從useEffect開始,並且僅在導致問題時才嘗試使用useLayoutEffect

據我所知,您的代碼正在按原樣工作。 下面的工作片段。

 const App = () => { React.useEffect(() => { window.scrollTo(0, 0); const // move queries outside of callback img = document.getElementById("logo-img"), name = document.getElementById("name"), handleLogoClasses = () => { const isTop = window.scrollY < 100; if (isTop) { img.classList.remove("logo-small"); name.classList.remove("no-display"); } else { img.classList.add("logo-small"); name.classList.add("no-display"); } } // call handleLogoClasses() or manually handle initial classes // handleLogoClasses() window.addEventListener("scroll", handleLogoClasses); // return a callback for cleanup return () => { window.removeEventListener("scroll", handleLogoClasses); } }, []); return ( <div className='scroll'> <div id='logo-img'> logo-img </div> <div id='name' > name </div> </div> ) } ReactDOM.render( <App />, document.getElementById("root") );
 .scroll { height: 200vh; } #logo-img { position:fixed; top: 0; left: 0; } #name { position:fixed; top: 40px; left: 0; }.logo-small { background-color: tomato; }.no-display { position:fixed; background-color: aquamarine; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <div id="root"></div>

我已將偵聽器回調移動到 function,並將查詢移到其外部以避免每次觸發事件時不必要的 DOM 交互。 我還添加了一個return回調刪除監聽器進行清理。 如果您想在scroll偵聽器觸發之前應用類名,只需調用回調或手動添加它們。

useEffect(() => {
  window.scrollTo(0, 0);

  const // move queries outside of callback
    img = document.getElementById("logo-img"),
    name = document.getElementById("name"),
    handleLogoClasses = () => {
      const isTop = window.scrollY < 100;

      if (isTop) {
        img.classList.remove("logo-small");
        name.classList.remove("no-display");
      } else {
        img.classList.add("logo-small");
        name.classList.add("no-display");
      }
    }

  // call handleLogoClasses() or manually handle initial classes
  // handleLogoClasses()

  window.addEventListener("scroll", handleLogoClasses);

  // return a callback for cleanup
  return () => {
    window.removeEventListener("scroll", handleLogoClasses);
  }
}, []);

使用參考()

利用useRef()可以避免直接查詢 DOM,而是讓 React 為您存儲元素。

 const App = () => { const img = React.useRef(), name = React.useRef(); React.useEffect(() => { window.scrollTo(0, 0); const handleLogoClasses = () => { const isTop = window.scrollY < 100; // access the elements stored in ref.current if (isTop) { img.current.classList.remove("logo-small"); name.current.classList.remove("no-display"); } else { img.current.classList.add("logo-small"); name.current.classList.add("no-display"); } } window.addEventListener("scroll", handleLogoClasses); // return a callback for cleanup return () => { window.removeEventListener("scroll", handleLogoClasses); } }, []); return ( <div className='scroll'> <div ref={img} id='logo-img'> logo-img (scroll to see change) </div> <div ref={name} id='name' > name </div> </div> ) } ReactDOM.render( <App />, document.getElementById("root") );
 .scroll { height: 200vh; } #logo-img { position:fixed; top: 0; left: 0; } #name { position:fixed; top: 40px; left: 0; }.logo-small { background-color: tomato; }.no-display { position:fixed; background-color: aquamarine; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <div id="root"></div>

const App = () => {
  const
    img = useRef(), name = useRef(); // <-- Declare refs

  React.useEffect(() => {
    ...
    
    const handleLogoClasses = () => {
      const isTop = window.scrollY < 100;

      if (isTop) {
        img.current.classList.remove("logo-small"); // <-- Access elements stored in ref
        name.current.classList.remove("no-display");
      } else {
       ...
      }
    }

    ...
  }, []);

  return (
    <div className='scroll'>
      <div ref={img} id='logo-img'> {/* <-- Assign element to ref */}
      ...
  )
}

使用狀態()

React 更喜歡使用 state 來處理樣式。 這允許您將所有className邏輯保留在jsx中,而不必在偵聽器回調中手動處理它,並且偵聽器只負責適當地設置 state。 這需要對您的初始window.scroll()進行單獨的useEffect()調用,該調用只會運行一次。 然后聲明一個isTop state 並將其添加到處理滾動監聽器的useEffect()的依賴數組中。 處理清理特別重要,因為每次 state 更改時都會重新創建偵聽器。

 const App = () => { const [isTop, setIsTop] = React.useState(true); React.useEffect(() => { window.scrollTo(0, 0); }, []) React.useEffect(() => { const handleIsTop = () => { const currentTop = window.scrollY < 50; if (currentTop;== isTop) { setIsTop(currentTop). } } window,addEventListener("scroll"; handleIsTop). return () => { window,removeEventListener("scroll"; handleIsTop), } }; [isTop]). return ( <div className='scroll'> <div id='logo-img' className={,isTop && 'logo-small'}> logo-img </div> <div id='name' className={.isTop && 'no-display'} > name </div> </div> ) } ReactDOM;render( <App />, document.getElementById("root") );
 .scroll { height: 200vh; } #logo-img { position:fixed; top: 0; left: 0; } #name { position:fixed; top: 40px; left: 0; }.logo-small { background-color: tomato; }.no-display { position:fixed; background-color: aquamarine; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <div id="root"></div>

const App = () => {
  const [isTop, setIsTop] = React.useState(true);

  React.useEffect(() => {
    window.scrollTo(0, 0);
  }, [])

  React.useEffect(() => {
    const
      handleIsTop = () => {
        const currentTop = window.scrollY < 100;

        if (currentTop !== isTop) {
          setIsTop(currentTop);
        }
      }

    window.addEventListener("scroll", handleIsTop);

    return () => window.removeEventListener("scroll", handleIsTop);
  }, [isTop]);

  return (
    <div className='scroll'>
      <div id='logo-img' className={!isTop && 'logo-small'}>
        logo-img
      </div>
      <div id='name' className={!isTop && 'no-display'} >
        name
      </div>
    </div>
  )
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM