[英]How do i properly use useEffect for a async fetch call with react? react-hooks/exhaustive-deps
[英]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
在與componentDidMount
和componentDidUpdate
相同的階段觸發。 但是,我們建議首先從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.