본문 바로가기

프로젝트/오심테(오늘의 심리테스트)

[리팩토링] 모바일 환경 반응성 추가 리팩토링 해보기

반응형

목표했던 기능 구현도 완료했고, 데이터도 많이 추가해 대략적으로 '오심테'를 완성한 것 같았다. 프로젝트 종료 예정일이였던 sqld 시험 전날까지 시간이 좀 남아 리팩토링을 해야겠다는 생각이 들었다. 디자인도 조금 더 손을 보고, 추가할만한 더 좋은 기능이 있으면 추가해보도록 해야겠다 싶어 지피티에게 물어보았다.

지피티의 대답은 이러했다. 꽤 좋은 아이디어들을 많이 제공해줬다. 3번을 제외하고는 시험 전 날까지 할 수 있는 만큼 해보려고 한다.

토이 프로젝트를 진행하면서 좋은 작업을 하셨습니다! 여러 가지 개선점을 고려하여 프로젝트를 보완할 수 있습니다. 아래는 몇 가지 제안 사항입니다:

1. 사용자 경험 개선: 현재 웹 사이트의 사용자 경험을 분석하고 개선할 수 있는 방법을 고려해보세요. 예를 들어, 사용자의 테스트 결과를 저장하고 추적할 수 있는 기능을 추가하거나, 사용자가 쉽게 카테고리를 선택하고 검색할 수 있는 필터링 기능을 도입할 수 있습니다.

2. 반응성 추가: 현재 프로젝트는 데스크톱 화면에 최적화되어 있습니다. 하지만 모바일 기기에서도 편리하게 사용할 수 있도록 반응형 디자인을 도입해보세요. 모바일 환경에서도 웹 사이트가 잘 보이고 사용하기 쉬워야 합니다.

3. 테스트 컨텐츠 확장: 현재는 몇 가지 테스트만 제공되고 있습니다. 테스트 컨텐츠를 추가하고 다양한 주제와 유형의 테스트를 제공하는 것이 좋습니다. 사용자들이 흥미로운 테스트를 더 많이 찾을 수 있고, 더 많은 방문자를 유도할 수 있습니다.

4. 시각적 개선: 웹 사이트의 디자인과 사용자 인터페이스를 더욱 매력적으로 만들 수 있습니다. 색상 선택, 폰트 스타일, 레이아웃 등을 개선하여 전체적인 시각적 품질을 높일 수 있습니다.

5. 소셜 공유 기능: 사용자가 테스트 결과를 소셜 미디어에 공유할 수 있는 기능을 추가하여 사용자들이 웹 사이트를 다른 사람들과 공유하고 홍보할 수 있도록 도와주세요.

오늘은 2번인 반응성 추가 항목을 건드려보았다. next/Image를 사용하여 이미지는 반응형에 최적화 되어 있었지만 나머지 컴포넌트는 그렇지 못해 모바일 환경을 고려하여 리팩토링을 해보았다.

가장 먼저 한 것은 헤더 내의 텍스트이다. 모바일 환경에서는 텍스트가 반응형으로 사이즈 조절이 되지 않아 두 줄로 떴다. 코드를 수정하여 뷰포트의 너비가 줄어듬에 따라 텍스트도 줄어들 수 있도록 하였다.

import { useEffect, useState, useCallback } from "react";

export default function Header({ handleReset }) {
  const [fontSize, setFontSize] = useState(37);

  useEffect(() => {
    const handleResize = () => {
      const viewportWidth = window.innerWidth;
      const calculatedFontSize = Math.min(viewportWidth / 20, 37);
      setFontSize(calculatedFontSize);
    };

    handleResize(); // 처음 렌더링될 때도 실행

    window.addEventListener("resize", handleResize);

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

  const handleClick = useCallback(() => {
    handleReset(true);
  }, []);

  return (
    <div
      className="h-24 w-screen flex justify-center items-center cursor-pointer 
    bg-gradient-to-r from-purple-300 via-purple-400 to-purple-300"
      onClick={handleClick}
      style={{ fontSize: `${fontSize}px` }}
    >
      <div className="font-semibold text-white cursor-pointer">
        오늘은 무슨 심리테스트를 해볼까?
      </div>
    </div>
  );
}

 

`handleResize` 함수는 화면 크기를 기반으로 폰트 크기를 계산하고, 그 값을 `setFontSize` 함수를 통해 상태로 관리한다. `window.innerWidth`를 사용하여 현재 뷰포트의 너비를 가져온 다음, 이를 기반으로 적절한 폰트 크기를 계산한다. 계산된 폰트 크기는 `setFontSize` 함수를 사용하여 `fontSize` 상태 변수에 저장된다.

`handleResize` 함수는 초기 렌더링 시 호출되고, 또한 윈도우의 크기가 변경될 때마다 호출된다. 이렇게 함으로써 화면 크기 변화에 따라 폰트 크기가 자동으로 조정된다.

`window.addEventListener("resize", handleResize)`를 사용하여 리사이즈 이벤트에 대한 이벤트 리스너를 등록한다. 이는 화면 크기가 변경될 때마다 `handleResize` 함수가 호출되도록 한다.

마지막으로, `return () => { window.removeEventListener("resize", handleResize); }`를 사용하여 컴포넌트가 언마운트될 때 리사이즈 이벤트 리스너를 정리한다. 이는 컴포넌트가 사라지거나 업데이트될 때 불필요한 이벤트 리스너가 남아있는 것을 방지하기 위해 사용된다.

결론적으로, 위의 코드는 화면 크기에 따라 폰트 크기를 자동으로 조정하고, 리사이즈 이벤트를 관리하는 기능을 제공한다.

두번째로 수정한 것은 반응형 margin이다. global.css에 다음과 같은 코드를 추가해주면 모바일 환경에서도 정돈된 UI를 볼 수 있다.

@media (max-width: 640px) {
  .mobile-width {
    padding: 0 16px;
  }
}

위 클래스를 원하는 컴포넌트에 적용시켜주면 끝!

import TestItem from "./testItem";

export default function TestList({ testList }) {
  return (
    <div className="mobile-width container mx-auto">
      <div className="mt-2 grid grid-cols-12 gap-4">
        {testList.map((test) => (
          <TestItem
            key={test.id}
            id={test.id}
            image={test.image}
            title={test.title}
            views={test.views}
          />
        ))}
      </div>
    </div>
  );
}

반응형