[React] 화면 사이즈 구하기 - resize 이벤트
본문 바로가기
더 알아보기/기능

[React] 화면 사이즈 구하기 - resize 이벤트

by 은돌1113 2022. 3. 4.
 

[React] resize 이벤트 다루기

✨ Window Resize 브라우저 화면 사이즈가 변경될 때, 변경된 사이즈 값을 리액트 컴포넌트에 적용할 수 있는 방법이 있다. 바로 window 객체에 발생되는 resize 이벤트를 감지하고, 그 때마다 컴포넌트

db2dev.tistory.com

 

내비게이션 바

Bootstrap의 강력하고 반응형적인 내비게이션 헤더, 내비게이션 바의 문서와 예. 콜랩스(collapse) 플러그인 지원을 포함한 브랜딩, 내비게이션 등의 지원이 포함되어 있습니다.

getbootstrap.kr

 

[Bootstrap] 부트스트랩 Navbar(메뉴 바) 사용 예제

부트스트랩 Navbar 설명 부트스트랩의 Navbar는 많은 웹페이지의 화면 상단에서 볼 수 있는 메뉴 바의 기본 틀을 제공합니다. 부트스트랩 사이트(https://getbootstrap.com/)의 Documentation 탭에서 Navbar를 검.

mjmjmj98.tistory.com


반응형 nav 만드려고 부트스트랩 사용해서 변형 시키다가 도저히 안되겠어서 화면 넓이를 활용하기로 했다.

부트스트랩은 그대로 사용하되 어느정도 넓이가 되면 className을 바꿔주는 방식으로 구현했다.

 

1. 아래 코드를 구현하고자 하는 페이지에 삽입한다. 아래 예제를 사용했는 데 삭제한 부분이 많다.

<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
  <!-- navbar-brand의 content 변경 -->
  <a class="navbar-brand" href="#">Fixed navbar</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarSupportedContent">
    <ul class="navbar-nav mr-auto">
      <li class="nav-item active">
        <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Link</a>
      </li>
      <!-- dropdown 메뉴 삭제 -->
      <li class="nav-item">
        <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
      </li>
    </ul>
    <form class="form-inline my-2 my-lg-0">
      <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" />
      <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
    </form>
  </div>
</nav>


출처: https://mjmjmj98.tistory.com/18 [Live passionate😎]

 

2. 1번에서 가져온 부트스트랩 코드를 내가 원하는 모습으로 변형 시킨다.

      <div className="navbar navbar-expand-md navbar-light bg-white fixed-top">
        <button
          className="navbar-toggler"
          type="button"
          data-toggle="collapse"
          data-target="#navbarSupportedContent"
          aria-controls="navbarSupportedContent"
          aria-expanded="false"
          aria-label="Toggle navigation"
          onClick={() => {
            setIsToggled(!isToggled);
          }}
        >
          <span className="navbar-toggler-icon"></span>
        </button>

        <div
          className="collapse navbar-collapse"
          id="navbarSupportedContent"
        ></div>
        <div className="navbar-collapse collapse" id="navbarSupportedContent">
          <a className="navbar-brand" href="/">
            <img width={90} height={30} src="" />
          </a>

          <ul className="navbar-nav">
            <li className="nav-item active">
              <a className="nav-link" href="#"></a>
            </li>
            <li className="nav-item active">
              <a className="nav-link" href="#"></a>
            </li>
            <li className="nav-item active">
              <a className="nav-link" href="#"></a>
            </li>
            <li className="nav-item active">
              <a className="nav-link" href="#"></a>
            </li>
          </ul>

          <ul className="navbar-nav">
            <li className="nav-item active userNav"></li>
            <li className="nav-item active userNav"></li>
            <li className="nav-item active userNav"></li>
          </ul>
        </div>
      </div>

 

3. CSS 작업한다. (이때 뭔가 CSS가 안먹는 것 같으면 !import를 뒤에 붙인다.)

 

4. 이 과정에서 resize 이벤트를 찾게 되었다. 블로그에 나와 있는 코드 중 아래 코드를 사용했다.

  const [resize, setResize] = useState();

  const handleResize = () => {
    setResize(window.innerWidth);
  };

  useEffect(() => {
    window.addEventListener("resize", handleResize);
    return () => {
      window.removeEventListener("resize", handleResize);
    };
  }, []);

이때 addEventListener를 사용하기 때문에 useEffect가 사라지는 시점에서 removeEventListener를 해줘야 한다.

 

아래 코드를 보면 위에 있는 코드와 달라진 점이 있다. 바로 resize event를 사용해서 얻어낸 resize state를 활용하여 width가 1100 보다 작으면 className을 바꿔줬다.

import { useState } from "react";

const Test = () => {

  .. 생략

  return (
    <>
		.. 생략
        
        <div
          className={
            resize <= 1100
              ? "collapse navbar-collapse-show"
              : "collapse navbar-collapse"
          }
          id="navbarSupportedContent"
        ></div>
        
        .. 생략
    </>
  );
};

export default Test;

여기서 왜 collapse navbar-collapse에서 collapse navbar-collapse-show가 되었냐면 -show 유무에 따라 toggle이 보이느냐 안보이느냐의 차이가 있기 때문이다.

 

5. 추가적으로 CSS에 아래 코드를 삽입 해줘야 한다.

#navbarSupportedContent {
  display: ${(props) => props.isToggled && "block"};
}

@media screen and (max-width: 1100px) {
  .navbar-toggler {
    display: block;
  }
}

 

6. 해결한 지 1시간 후 문제 발생 보자마자 뭐라는 거지라고 생각했다. 

 

Next.js는 SSR 즉, Server Side Rendering이고, window, document와 같은 브라우저 전역 객체는 Client Side Rendering에서 일어난다. (SSR 실행 -> CSR 실행)

 

나는 innerWidth만 구하면 되는 거라서 구글링으로도 답을 찾을 수 없었다.

얻은 거라고는,, next/dynamic을 사용하거나 useEffect를 사용 해야 한다는 점???

그러다 문득 Zzz 프로젝트 할 때 팀원분이 setTimeout으로 데이터 불러와 지지 않는 문제를 해결하셨던 게 기억났다.

(항상 팀원들에게 도움을 받는 것 같다.)

 

그래서 4번에서 진행했던 코드를 아래와 같이 수정했다. (useEffect 부분만 수정했다.)

  useEffect(() => {
    window.addEventListener("resize", () => {
      setResize(window.innerWidth);
    });

    const time = setTimeout(() => {
      console.log(window.innerWidth);
      setResize(window.innerWidth);
    }, 0.0000000000000000001);

    return () => {
      window.removeEventListener("resize", () => {
        setResize(window.innerWidth);
      });

      clearTimeout(time);
    };
  }, []);

addEventListener은 새로고침 안된 상태에서 화면 넓이가 달라질 때 CSS 적용하고,

setTimeout은 새로고침 시 처음에 화면 넓이를 가져온다.

(둘 중 하나만 썼더니 뭔가 하나씩 안된다..)

댓글