IntersectionObserver 사용하기 + React : received `false` for a non-boolean attribute 오류 수정

GOGO·2024년 9월 11일
0

1.IntersectionObserver로 scroll 감지하기

포트폴리오 만들던 중에 사용하게 되었다. 앞으로도 자주 쓸 것 같아서 기록해놓기

뭘 하고싶었냐면

  1. Experience 영역에만 네비게이션 만들어서 이동시키기
  2. 스크롤해서 각 항목 영역에 들어갔을 때 해당하는 nav 제목 활성화(스타일 active)
  3. 각 nav 클릭했을 때도 스타일 변경

이동은 첨에 그냥 a 태그로 만들었는데 그럼 id가 주소 뒤에 붙는게 싫어서 useRef랑 scrollIntoView()를 써보기로 했다.

    const careerRef = useRef(null);
    const projectRef = useRef(null);

    const handleNavClick = (ref) => {
      if (ref.current) {
        ref.current.scrollIntoView();
      }
    };

	...
    <Nav>
      <NavItem 
        onClick={() => handleNavClick(careerRef)}
      >
        Career
      </NavItem>
      <NavItem 
        onClick={() => handleNavClick(projectRef)}
      >
        Project
      </NavItem>
    </Nav>

	<Career id="career" ref={careerRef}></Career>
	<Project id="project" ref={projectRef}></Project>

scrollIntoView는 특정 element 기준으로 스크롤을 이동시키는 거라서 Career 영역과 Project영역에 각각 ref={careerRef}, ref={projectRef}로 위치를 주고 handleNavClick 이벤트로 이동하게 했다.

이제 영역이 보이면 nav의 해당 항목을 활성화 시켜보자.
IntersectionObserver는 Target Element가 노출되었는지 여부를 감시할 수 있는 API이다.

    const careerRef = useRef(null);
    const projectRef = useRef(null);
    const [activeSection, setActiveSection] = useState('');

    useEffect(() => {
      const careerArea = careerRef.current;
      const projectArea = projectRef.current;

      const observerOptions = {
        root: null,
        rootMargin: '0px',
        threshold: 0.3,
      }

      const observer = new IntersectionObserver((entries) => {
        entries.forEach((entry) => {
          if (entry.isIntersecting) {
            setActiveSection(entry.target.id);
          }
        })
      }, observerOptions)

      if (careerArea) observer.observe(careerArea);
      if (projectArea) observer.observe(projectArea);

      return () => {
        observer.unobserve(careerArea);
        observer.unobserve(projectArea);
      };
    }, [])

	...
    
    <Career id="career" ref={careerRef}></Career>
	<Project id="project" ref={projectRef}></Project>

IntersectionObserver 옵션은 세가지가 있다.
1. root : root 로 정의된 Element 기준으로 Target Element 의 노출, 비노출 여부를 결정, 기본 값은 Browser ViewPort
2. rootMargin : rootMargin 이 있으면, threshold 계산할 때 rootMargin 영역 만큼 더 계산
3. threshold : 정의한 퍼센트 만큼 노출 (여기서는 0.3을 줬는데 섹션의 30%가 보이면 활성화 하겠다는 거다)

Career과 Project 태그에 id를 주고 isIntersecting으로 노출 여부를 판단, setActiveSection를 target.id로 설정해서 activeSection을 career 또는 project로 만든다.

그리고 나서 스타일 주기

  const NavItem = styled.p`
    font-size: 3.5rem;
    cursor: pointer;
    color: #EEEEEE0D;
    transition: .3s;
    ${({ $active }) => $active && 'font-size: 3.8rem; transition: .3s; color: #EEEEEE;'};
	`
  ...
  
  <Nav>
    <NavItem 
      $active={activeSection === 'career'}
      onClick={() => handleNavClick(careerRef)}
      >
      Career
    </NavItem>
    <NavItem 
      $active={activeSection === 'project'}
      onClick={() => handleNavClick(projectRef)}
      >
      Project
    </NavItem>
  </Nav>
  

styled-components를 사용하기 때문에 $active를 props로 activeSection의 값에 따라 active 되고 있는 항목의 스타일을 변경할 수 있다~

$를 붙인 이유는... 아래에

2. React : received false for a non-boolean attribute 오류 수정

스타일 컴포넌트로 작업하다 보면 심심찮게 이런 형식의 오류가 보이곤 한다...
props로 전달하려는 속성이 DOM 요소로 그대로 전달되기 때문에 오류를 발생시킬 수 있어서 뜨는 오류라고 한다. 얘 입장에서는 HTML의 표준 속성에는 그런 값이 없는데? 전달이 되니 오류가 생긴것

공식문서에 잘 나와있...고 나와 같은 상황에 갇혔던 여러분의 도움으로 보다 쉽게 해결할 수 있었다.

(공식문서를 잘 읽자)

바로바로!! $ 붙이기

휴... 이렇게 해주면 Html attribute로 전달되지 않고 style로만 기능할 수 있게 된다!!

깨끗해진 콘솔창이 내 마음도 깨끗하게 만들어 주었다

참고: https://pks2974.medium.com/intersection-observer-간단-정리하기-fc24789799a3
감사합니닷...

profile
#💻 #FE #💡 #📓

0개의 댓글