사용하기 나름이겠지만 navBar를 기준으로 io를 구현해보자.
요청받은 사항은 아래의 두가지 였다.
화면의 최상단에 있는 경우 navBar의 배경색을 투명하게한다.
스크롤이 내려가면 화면을 따라 navBar가 따라오고 배경색이 흰색이 된다.
<nav>
...
</nav>
위와 같이 nav 태그 내부에 당신의 navBar가 있다고 하자.
lint에 오류가 있지만 상관하지 않고 기능을 구현하기로한다
우선 dom의 형태를 변경해준다.
<div>
<div /> // 1
<nav> // 2
...
</nav>
</div>
위와 같은 형태를 한 이유는 nav 태그 위의 div가 필요해서이다.
1의 역할은 화면에 보이면 false를 반환한다라는 이벤트를 하는 io를 심어놓는다.
2의 역할은 화면에 안보이면 true를 반환한다라는 이벤트를 하는 io를 심어놓는다.
즉 스위치를 만든 것이다.
아래는 실제 코드의 일부이다.
const Navigation = () => {
const [showMenu, setShowMenu] = useState(false);
const toggleMenu = () => setShowMenu(!showMenu);
const [isNavBgVisible, setIsNavBgVisible] = useState(false);
const navIoRef = useRef<any>();
const ceilingIoRef = useRef<any>();
const topObCallBack = () => {
setIsNavBgVisible(false);
};
const navObCallBack = () => {
console.log(`callback!`);
setIsNavBgVisible(true);
};
useEffect(() => {
const observeWhenNavDisappear: IntersectionObserver = new IntersectionObserver(([entries]: any): void => {
if (!entries.isIntersecting) {
navObCallBack();
observeWhenNavDisappear.unobserve(entries.target);
}
});
// lint error
navIoRef.current && observeWhenNavDisappear.observe(navIoRef.current);
}, [navIoRef, isNavBgVisible]);
useEffect(() => {
const observeWhenCeilingAppear: IntersectionObserver = new IntersectionObserver(([entries]) => {
if (entries.isIntersecting) {
topObCallBack();
}
});
// lint error
ceilingIoRef.current && observeWhenCeilingAppear.observe(ceilingIoRef.current);
}, [ceilingIoRef, isNavBgVisible]);
return (
<div>
<div ref={ceilingIoRef} />
<nav
ref={navIoRef}
className={tw(`bg-white ${isNavBgVisible ? `bg-opacity-100 fixed` : `bg-opacity-0 `} absolute z-20 w-full`)}
>
...
</nav>
...
</div>
react의 life cycle을 고려하여 useEffect와 useRef를 사용해야 한다.
문법적으로 걸리는 부분은 주석으로 lint error
이라 써놓았고
ref를 선언하는데 any 타입을 사용한 것이다.
하지만 위 코드의 일부는 landingpage에서 사용되고 nextjs를 거쳐 compile되기 때문에 결국 static한 html 파일이 된다.
따라서 lint나 type 선언이 지저분해도 어느정도는 감안이 되는 부분이다.
잘 생각해보면 useEffect와 io 하나에 모든 기능을 넣을 수 있겠지만
굳이 그래야 하는가? 라는 생각도 들어 useEffect를 두개로 나누었다.