내일배움캠프

230808 useViewport()로 미디어 쿼리 없이 반응형 만들기

Neda 2023. 8. 8. 20:31

230808 useViewport()로 미디어 쿼리 없이 반응형 만들기

이번 프로젝트는 처음부터 반응형을 고려하고 만들기로 했다. Ant Design 라이브러리를 사용하기 때문에 전체 레이아웃은 Ant Design의 Layout 컴포넌트를 사용했다.Ant Disign에서는 Layout 컴포넌트를 import 한 다음 구조분해할당을 통해 다시 빼는 방식을 사용했다.

이렇게 사용하기 때문에 Header 컴포넌트를 자동완성으로 가져올 수는 없다

import { Layout } from 'antd';
const { Header, Content, Footer, Sider } = Layout;

<Layout.Header></Layout.Header>
<Header></Header>

 

Layout 컴포넌트를 반응형으로

이러한 Layout 컴포넌트에는 style props를 통해 직접 스타일 지정해 줄 수도 있지만, width속성을 통해 숫자나 문자열로 값을 지정할 수도 있다. 이 부분을 뷰포트 사이즈에 따라 바꿔주면 미디어 쿼리 없이도 반응형을 할 수 있었다.

import { Layout } from 'antd'

const { Sider } = Layout

const Sidebar = ({open, setOpen}:Props) => {
  const {width} = useViewport()
  return (
    <Sider width={width < 800 ? '100%': 360} ...>
        ...
    </Sider>
  )
}

export default Sidebar

 

useViewport()

이 커스텀 훅은 직접 구현할까 하다가 저번에 본 글이 기억나 가져와서 사용하게 되었다.

역할은 resize()가 될 때마다 window 전역 객체에서 innerWidth, innerHeight 값을 가져와서 가지고 있는다.

더 발전시키면 Mobile, Table, Desktop 와 같이 3개 이상으로 더 세분화하여 나눌 수 있을 것 같다

import {
  useLayoutEffect,
  useState,
} from 'react';

function useViewport() {
  const [width, setWidth] = useState(0);
  const [height, setHeight] = useState(0);
  const [isMobile, setIsMobile] = useState(false);
  const [isLoaded, setIsLoaded] = useState(false);

  const handleResize = () => {
    setWidth(window.innerWidth);
    setHeight(window.innerHeight);
    setIsMobile(window.innerWidth <= 768 || window.outerWidth <= 768);
  };

  useLayoutEffect(() => {
    handleResize();
    setIsLoaded(true);
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return {
    width,
    height,
    isMobile,
    isLoaded,
  };
}

export default useViewport;
 

styled-components 환경에서 효율적으로 반응형 처리하기

조금 더 리액트스럽게 퍼블리싱 하기 위한 고민을 담았습니다.

blog.payhere.in