2023. 10. 12. 21:50ㆍProject Tours/Tour on PR
0. 나는 왜 이것을 만드는가?
> 지난주 나는 이력서를 여기저기 넣었다. 놀랍게도... 조용했다. 아무도 다시 회신을 준 기업이 없었다. 사실 부족하다고는 생각했는데 이렇게까지 연락이 안올 줄은 몰랐다. 뭔가 전달 방식이 잘못되었나? 아님 코드로 아직 부족한 점이 많은가? 정말 많은 고민이 되었다. 문제가 2가지 다라고 생각해서 내 브랜딩 페이지를 만들어 보는 것이 해결책이 되지 않을까 생각이 되었다. 이 페이지를 최대한 현실 서비스 웹페이지를 만든가 가정하고 만들어보고 내 생각을 구현하기 위해 어떻게 했는지 기록해보기로 했다. 이렇게 했는데도 만약 안되면 아직 공부가 부족하거나 운이 없거나 개발자 될 운명이 아닌 걸로 알아야겠다.
1. 기획
> 먼저 몇 가지 웹페이지의 목적을 분명히 했다.
1. 내가 어떤 개발자이고 어떤 기술에 관심있는지 보여줘야한다.
- 나는 코드 재사용성에 대해 고민한다. - 폴더 구조를 통해 재사용성이 될 만한 코드를 파악해 별도로 뽑는다.
- 나는 성능 최적화에 관심이 있다. - 라이트하우스 90점을 넘어보자.
2. 내가 생각을 코드로 구현할 수 있음을 보여줘야한다.
- 여러가지 Web API를 활용해보자
- 여러가지 라이브러리도 활용해보자
- 라이브러리 없이 한 번 만들어보자
2. 오늘의 문제: 일정 위치에서 글자 사라지게 하기

> 먼저 첫페이지를 만들었는데 이 글자들이 네비게이션바에 닿기전에 사라지는 기능이 있으면 좋겠다고 생각했다.

> 안그러면 네이게이션 바하고 겹치는 문제가 발생했다.
2-1 scroll 이벤트
> 처음 생각했던 방안은 scroll 이벤트였다. 얼마큼 내려왔는지 체크하고 없애는 방식인데 나머지도 그렇게 처리하기에는 계산해야될 것이 많아 좋은 방법이 아니라고 생각했다. getBoundingClientRect() 통해서 엘리먼트의 각 상하좌우 바깥 좌표값을 찾고 설정하려니 머리가 벌써 아파왔다.
2-2 Intersection Observer API
https://www.youtube.com/watch?v=e4Afka5IOZ8&ab_channel=%EC%BD%94%EB%94%A9%EC%95%A0%ED%94%8C
> 예전에 애플 코딩에서 스크롤 애니메이션에 대한 내용을 보았다. 여기서는 엘리먼트를 관찰하고 있다가 뷰포트에 진입을 할 때 이벤트를 처리하는 것이다. 반대로 생각하면 관찰 대상이 벗어날 때 처리도 가능하다는 이야기가 되기에 API를 활용해보기로 하였다. 사실 나같은 기능을 만들려는 사람이 많을텐데 구글에서 관련 기능에 대한 블로그 글이 없어서 내심 놀랐다. 물론 내가 검색을 잘 못한거라고 생각이 든다.
실무에서 느낀 점을 곁들인 Intersection Observer API 정리
실무에서 Intersection Observer API를 사용해보고 느낀 생각정리
velog.io
> 엄청 잘 정리된 글을 발견했다. 두 기능을 비교한 주요 골자는 이러하다.
- scroll 이벤트는 지속적으로 이벤트가 호출되어 메인 스레드에 부하를 줄 수 있다. 실제로 scroll로 구현했는데 스크롤이 움직일 때마다 이벤트 콜백이 불러져와 걱정되는 부분이었다. 무엇보다도 reflow가 발생에 성능에 악영향을 준다.이 부분을 잡을 수 없다면 어쩔 수 없지만 Intersection Observer는 이 부분을 해결해준다.
- Intersection Observer의 가장 큰 차이점은 비동기적으로 작동한다고 한다. 그리고 가시성을 구분할 때 reflow를 발생시키지 않기에 성능의 이점을 가져갈 수 있다.


- 공식 문서에서는 getBoundingClientRect() 계산하는데 있어 성능 문제를 우려하고 있고 마지막 하단에 이 api는 단지 교차되는 것만을 고려하기 때문에 성능 문제를 해결할 수 있음을 간접적으로 이야기해 준다. 읽어보니 위에 정리된 글은 공식 문서를 실제로 실행해본 글이었다.
Intersection Observer API - Web APIs | MDN
The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport.
developer.mozilla.org
3. 적용
import { useRef, useEffect } from "react";
import "./home.scss";
import scroll_hand from "./assets/images/icons/scoll_hand.png";
const Home = () => {
const mainTitleRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
if (!mainTitleRef.current) return;
const callback = (entries: IntersectionObserverEntry[]) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
console.log("hi")
entry.target.classList.remove("disappear")
} else {
console.log("bye for now")
entry.target.classList.add("disappear")
}
});
};
const options = { root: null, rootMargin: "-500px 0px 0px 0px" };
const observer = new IntersectionObserver(callback, options);
observer.observe(mainTitleRef.current);
return () => {
observer.disconnect();
};
}, []);
return (
<div className="home_container">
<div className="home_nav">
<span>KesKnowsNothing</span>
<span>letmeknowkes@gmail.com</span>
<span>job seeker</span>
</div>
<div className="home_main">
<span className="main_title" ref={mainTitleRef}>
Developing something is like a jounery
</span>
<span className="main_intro">
프론트엔드의 기초 체력, 탄탄한 자바스크립트 지식을 쌓은 케스입니다.
</span>
<span className="main_intro">
기능 구현을 넘어 코드의 재사용성과 웹페이지 성능 최적화를 좋아합니다.
</span>
<span className="main_intro">
개발은 저에게 여행과도 같아서 오늘도 코드 위로 떠나보려합니다.
</span>
</div>
<div className="scroll_wrapper">
<span>Scroll Jounery</span>
<img src={scroll_hand} alt="scroll_hand" />
</div>
</div>
);
};
export default Home;
> 나같은 경우는 네이게이션 바를 만나기 전에 없어져야 하므로 option 값에 -를 해주었다. 영역을 조절할 수 있다는 점에서 아주 유용했다. 아래도 처리해야겠다.
