reactスクロール時のナビゲーションの変換



進行中のアヒルのプロジェクトのテーマ詳細ページには、スクロールナビゲーションバーの色変換のデザインが表示されます.スクロール位置の決定方法を考えた場合、IntersectionObserverを使用することを決定します.

1.チェックマーク位置

const option = {};
const isRef = useRef<HTMLElement | null>(null);

useEffect(() => {
    const observer = new IntersectionObserver((entry) => {
      if (entry[0].isIntersecting) {
        console.log("여깁니다")
      }
    }, option);

    if (isRef.current) {
      observer.observe(isRef.current);
    }

    return () => observer.disconnect();
  }, []);

return (
    <section>
      <ThemeHeader />
      <ThemeNav />
      <ThemeExplain ref={isRef}/>
      <ThemeAnalysis />
      <ThemeEvent />
      <ThemeRevie />
      <ReviewBottom />
    </section>
  );
1.eEffect内でIntersectionObserverを使用してrefを検出し、ラベルが画面に表示されるとともに、isIntersectionのtrueを確認するとコンソールが撮れる.
2.各部分に1つのIntersectionObserverが必要に見えるので、複数のコードを作成するとコードが乱れる可能性があると思いますので、CustomHookにするべきだと思います.

2.Custom Hookで減算

// useThemeObserver.ts
import { useEffect, useRef } from 'react';

export const useThemeObserver = (
  setState: React.Dispatch<React.SetStateAction<number>>,
  stateNumber: number,
): React.MutableRefObject<HTMLElement | null>[] => {
  const isRef = useRef<HTMLElement | null>(null);
  const option = {};

  useEffect(() => {
    const observer = new IntersectionObserver((entry) => {
      if (entry[0].isIntersecting) {
        setState(stateNumber);
      }
    }, option);

    if (isRef.current) {
      observer.observe(isRef.current);
    }

    return () => observer.disconnect();
  }, []);

  return [isRef];
};
Custom Hook内でステータス番号を指定し、番号の値でナビゲーションバーを区別することを決定します.

3.ラベルによるuserefの指定

const ThemeDetailTemplate = (): ReactElement => {
  const [navNumber, setNavNumber] = useState(1);
  
  const [explainRef] = useThemeObserver(setNavNumber, 1);
  const [analysisRef] = useThemeObserver(setNavNumber, 2);
  const [eventRef] = useThemeObserver(setNavNumber, 3);
  const [reviewRef] = useThemeObserver(setNavNumber, 4);

  return (
    <section>
      <ThemeHeader />
      <ThemeNav position={navNumber} />
      <ThemeExplain isRef={explainRef} />
      <ThemeAnalysis isRef={analysisRef} />
      <ThemeEventisRef={eventRef}/>
      <ThemeReview isRef={reviewRef} />
      <ReviewBtn/>
    </section>
  );
};

export default ThemeDetailTemplate;
  • 画面では、必要な部分が表示されるたびに、各部分の番号を知るためにsetStateに値を変更できます.
  • しかし、レイアウトの高さが狭いためか、スクロール中に1番から3番に直接ジャンプするバグがありました.
  • 4.rootMarginを使用して一部の位置を縮小

    //usethemeObserver.ts
    const option = { threshold: 0, rootMargin: `-${document.body.scrollHeight / 2 - 1}px 0px` };
    IntersectionObserverのオプションでは、rootMarginの値は画面の高さの半分よりやや小さく、中央を通るときにステータス番号を変更することができ、1から3への移行を防ぐことができます.

    5.ナビゲーションバーcssの適用

    //ThemeNav.tsx
    interface Props {
      position: number;
    }
    const ThemeNav = ({ position }: Props): ReactElement => {
      const arr = [
        { id: 1, content: '테마' },
        { id: 2, content: '분석' },
        { id: 3, content: '이벤트' },
        { id: 4, content: '리뷰' },
      ];
    
      return (
        <S.Nav>
          {arr.map((ar) => (
            <S.Box key={ar.id} border={position === ar.id}>
              <S.PTag border={position === ar.id}>{ar.content}</S.PTag>
            </S.Box>
          ))}
        </S.Nav>
      );
    };
    ナビゲーションバーとpropsで受信したstate値が同じ場合のboolean値をstyled-componentに変換し、state値を変更するたびにcss変換を試みます.