[英]How to rid error of null properties in react hook?
我正在嘗試自定義掛鈎以獲取少量數據。 我想檢查一個元素與第二個元素相比在哪里。 我想把它放在他們中間。 它有效,但我在控制台中重復出現錯誤。
錯誤:
未捕獲的類型錯誤:無法在 getPosition (usePosition.js:18:1) 讀取 null 的屬性(讀取“offsetLeft”)
import { useEffect, useRef, useState } from "react";
const usePosition = () => {
const elRef = useRef();
const elSecondRef = useRef();
const [fromLeftEl, setFromLeftEl] = useState();
const [fromTopEl, setFromTopEl] = useState();
const [widthEl, setWidthEl] = useState();
const [heightEl, setHeightEl] = useState();
const [widthElSecond, setWidthElSecond] = useState();
const [finalX, setFinalX] = useState();
const [finalY, setFinalY] = useState();
// This function calculates the position underneath the element and centering it with respect to the other element
const getPosition = () => {
const fromLeftEl = elRef.current.offsetLeft;
setFromLeftEl(fromLeftEl);
const fromTopEl = elRef.current.offsetTop;
setFromTopEl(fromTopEl);
const widthEl = elRef.current.offsetWidth;
setWidthEl(widthEl);
const heightEl = elRef.current.offsetHeight;
setHeightEl(heightEl);
const widthElSecond = elSecondRef.current.offsetWidth;
setWidthElSecond(widthElSecond);
const middleEl = widthEl / 2;
const middleElSecond = widthElSecond / 2;
const finalX = fromLeftEl + middleEl - middleElSecond;
setFinalX(finalX);
const finalY = fromTopEl + heightEl;
setFinalY(finalY);
};
// Get the position of the first element
useEffect(() => {
getPosition();
}, []);
useEffect(() => {
window.addEventListener("resize", getPosition);
window.addEventListener("click", getPosition);
window.addEventListener("scroll", getPosition);
return () => window.removeEventListener("scroll", getPosition);
}, []);
return {
elRef,
elSecondRef,
fromLeftEl,
fromTopEl,
widthEl,
heightEl,
finalY,
finalX,
widthElSecond,
};
};
export default usePosition;
使用 usePosition 的組件:
import classNames from "classnames";
import { useState } from "react";
import useSticky from "./useSticky";
import usePosition from "./usePosition";
import "../style/sass/Nav.sass";
import { NavLink } from "react-router-dom";
const Nav = (props) => {
const [isActive, setActive] = useState(false);
const { sticky, stickyRef } = useSticky();
const { elRef, elSecondRef, finalY, finalX } = usePosition();
const handleToggle = () => {
setActive(!isActive);
};
return (
<div
ref={stickyRef}
className={classNames("nav", { sticky })}
style={{
display: props.display,
height: sticky ? `${stickyRef.current?.clientHeight}px` : "10vh",
width: props.width,
gridTemplateColumns: props.navGridCol,
gridTemplateRows: props.navGridRow,
height: props.height,
position: props.position,
left: props.left,
animation: props.animationMenu,
}}
>
<div
className="nav__logo"
style={{
gridArea: props.gArea1,
height: props.heightHomeBtn,
width: props.btnWidth,
animation: props.animationHome,
display: props.homeDisplay,
}}
>
<NavLink className="link__logo" to="/">
<i
class="icon-home"
style={{
width: props.btnWidth,
fontSize: props.fweight,
}}
></i>
</NavLink>
</div>
<NavLink
className="link__about"
to="/about"
exact="true"
style={{ gridArea: props.gArea2 }}
>
<button
className="nav__aboutBtn"
style={{
height: props.btnHeight,
width: props.btnWidth,
animation: props.animationAbout,
display: props.aboutDisplay,
}}
>
<p>o firmie</p>
</button>
</NavLink>
<button
onClick={handleToggle}
className={!isActive ? "offerDD__btn" : "offerDD__btn_active"}
style={{
gridArea: props.gArea3,
height: props.btnHeight,
width: props.btnWidth,
animation: props.animationOffer,
display: props.offerDisplay,
}}
ref={elRef}
>
<i class="icon-down-open"></i>
<p>oferta</p>
</button>
<div
className={
!isActive ? "offerDD__dropdown_disabled" : "offerDD__dropdown"
}
ref={elSecondRef}
style={{ top: `${finalY}px`, left: `${finalX}px` }}
>
<NavLink className="link__air" to="/air-conditioning">
<div
className="air__p"
style={{ height: props.btnHeight, width: props.btnWidth }}
>
<p>klimatyzacje</p>
</div>
</NavLink>
<NavLink className="link__vent" to="/ventilation">
<div
className="vent__p"
style={{ height: props.btnHeight, width: props.btnWidth }}
>
<p>wentylacje</p>
</div>
</NavLink>
<NavLink className="link__heat" to="/heat-pump">
<div
className="heat__p"
style={{ height: props.btnHeight, width: props.btnWidth }}
>
<p>pompy ciepła</p>
</div>
</NavLink>
<NavLink className="link__recu" to="/recuperation">
<div
className="recu__p"
style={{ height: props.btnHeight, width: props.btnWidth }}
>
<p>rekuperacja</p>
</div>
</NavLink>
<NavLink className="link__fire-protection" to="/fire-protection">
<div
className="fire__p"
style={{ height: props.btnHeight, width: props.btnWidth }}
>
<p>ppoż</p>
</div>
</NavLink>
<NavLink className="link__shop" to="/shop">
<div
className="shop__p"
style={{ height: props.btnHeight, width: props.btnWidth }}
>
<p>sklep</p>
</div>
</NavLink>
</div>
<NavLink
className="link__blog"
to="/blog"
style={{ gridArea: props.gArea4 }}
>
<button
className="nav__blogBtn"
style={{
height: props.btnHeight,
width: props.btnWidth,
animation: props.animationBlog,
display: props.blogDisplay,
}}
>
<p>blog</p>
</button>
</NavLink>
<NavLink
className="link__contact"
to="/contact"
style={{ gridArea: props.gArea5 }}
>
<button
className="nav__contactBtn"
style={{
height: props.btnHeight,
width: props.btnWidth,
animation: props.animationContact,
display: props.contactDisplay,
}}
>
<p>kontakt</p>
</button>
</NavLink>
<NavLink
className="link__login"
to="/login"
style={{ gridArea: props.gArea6 }}
>
<button
className="nav__loginBtn"
style={{
height: props.btnHeight,
width: props.btnWidth,
animation: props.animationLogin,
display: props.loginDisplay,
}}
>
<p>zaloguj</p>
</button>
</NavLink>
</div>
);
};
export default Nav;
我想知道如何在控制台和工作掛鈎中正確編碼這個問題而不會出錯。
我知道這個錯誤是由於無法讀取不存在的東西而導致的,因此它是 null 但如何編寫此代碼以使其正確?
我沒有看到在消費組件中使用elRef
的方式有任何明顯的問題。 elRef
附加到 DOM 元素,例如button
,並且沒有條件渲染,因此button
在初始渲染期間渲染到 DOM。
const Nav = (props) => {
...
const { elRef, elSecondRef, finalY, finalX } = usePosition();
...
return (
<div
...
>
...
<button
onClick={handleToggle}
className={!isActive ? "offerDD__btn" : "offerDD__btn_active"}
style={{
gridArea: props.gArea3,
height: props.btnHeight,
width: props.btnWidth,
animation: props.animationOffer,
display: props.offerDisplay,
}}
ref={elRef}
>
<i class="icon-down-open"></i>
<p>oferta</p>
</button>
...
</div>
);
};
但是,我確實在usePosition
掛鈎中看到了潛在的問題。 掛鈎不會清除它創建的所有效果。 在訪問潛在的 null 或未定義引用的情況下,建議在訪問屬性之前使用空檢查/保護子句或可選鏈接運算符。 在這種情況下,用於檢查 refs 是否具有真實當前值的if
塊就足夠了。
const usePosition = () => {
const elRef = useRef();
const elSecondRef = useRef();
const [fromLeftEl, setFromLeftEl] = useState();
const [fromTopEl, setFromTopEl] = useState();
const [widthEl, setWidthEl] = useState();
const [heightEl, setHeightEl] = useState();
const [widthElSecond, setWidthElSecond] = useState();
const [finalX, setFinalX] = useState();
const [finalY, setFinalY] = useState();
// This function calculates the position underneath the element and centering it with respect to the other element
const getPosition = () => {
// Only access ref properties if there is a current value
if (elRef.current && elSecondRef.current) {
const fromLeftEl = elRef.current.offsetLeft;
setFromLeftEl(fromLeftEl);
const fromTopEl = elRef.current.offsetTop;
setFromTopEl(fromTopEl);
const widthEl = elRef.current.offsetWidth;
setWidthEl(widthEl);
const heightEl = elRef.current.offsetHeight;
setHeightEl(heightEl);
const widthElSecond = elSecondRef.current.offsetWidth;
setWidthElSecond(widthElSecond);
const middleEl = widthEl / 2;
const middleElSecond = widthElSecond / 2;
const finalX = fromLeftEl + middleEl - middleElSecond;
setFinalX(finalX);
const finalY = fromTopEl + heightEl;
setFinalY(finalY);
}
};
useEffect(() => {
window.addEventListener("resize", getPosition, { passive: true });
window.addEventListener("click", getPosition);
window.addEventListener("scroll", getPosition, { passive: true });
// Call once on initial component render
getPosition();
// Return cleanup function to remove all listener callbacks!
return () => {
window.removeEventListener("resize", getPosition, { passive: true });
window.removeEventListener("click", getPosition);
window.removeEventListener("scroll", getPosition, { passive: true });
};
}, []);
return {
elRef,
elSecondRef,
fromLeftEl,
fromTopEl,
widthEl,
heightEl,
finalY,
finalX,
widthElSecond,
};
};
export default usePosition;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.