frontend

[REACT] 재사용성 컴포넌트

프론트엔드코린이 2025. 1. 20. 17:47

재사용성 컴포넌트 정의

  • 중복되는 코드를 함수(컴포넌트)로 지정하여 사용하는 곳에 이름을 호출하여 사용한다고 생각한다

재사용 가능한 컴포넌트를 사용하는 목적

  • 반복되는 코드가 100만 개 있다고 가정해 보자! "프코님, 버튼 오늘까지 수정해 주세요"라고 요청받았는데, 그 해당 버튼은 이곳저곳 100만 개가 사용된다고 생각해 보자.
  • 하나씩 고치다 보면 절대 시간 안에 못 끝낸다
  • 이러한 문제점을 하나의 함수로 정의하여 사용했더라면? 그 함수만 수정하면 사용되는 부분도 자동으로 수정되는 거 아닌가?

요구사항.. 멈춰!!!

 

※ 이러한 문제들이 발생하여 궁극적으로는 재사용이 가능한 컴포넌트를 사용하는 이유는 추후 유지보수에 편리하기 위해 사용한다고 나는 정의할 수 있다.

 

  • 아래의 코드를 살펴보자
export default function Home() {
  return (
    <div className="w-full mx-auto flex flex-col gap-6 p-12">
      <button className="animate-fadeIn">fadeIn</button>
      <button className="animate-slideIn">slideIn</button>
      <button className="animate-scaleUp">scaleUp</button>
      <button className="animate-rotate">rotate</button>
    </div>
  );
}
  • 위 코드에서 동일한 형태의 버튼 태그를 본다면... 내 직업이 개발자라면? 무조건 고쳐야 한다!!
  • 그럼 중복되는 버튼 태그를 하나의 함수(컴포넌트)로 정의하여 사용하는 코드를 살펴보자
//components -> Button.jsx

import React from "react";

export default function Button({ children, animation = "scaleUp" }) {  
return <button className={`inline-block font-bold bg-blue-500 p-2 hover:animate-${animation}`}>
    {children}
    </button>
}
//page -> index.js  
import Button from "@/components/Button";

export default function Home() {  
return (
  <h1 className={font-bold text-3xl}>hello wolrd</h1>
  <Button children={"fade in"} animation="fadeIn" />  
  <Button children={"slide in"} animation="slideIn" />  
  <Button children={"scale up"} animation="scaleUp" />  
  <Button children={"rotate"} animation="rotate" />
);  
}
  • 위와 같이 components 폴더에 Button 컴포넌트를 하나 만들어서, Home컴포넌트에 사용해 보는 방법으로 고쳐보았다.

위 형태로 브라우저에 랜더링 되는 것을 확인할 수 있다.

 

 

애니메이션이 잘 작동되는지 테스트를 해봤다.. 두근.. 두근...?

동작하지 않는다... 여기서 문제점을 발견했다면 당신은 개발 고수일 것이다.

※ hint

  1. 내가 사용한 CSS 기법은 유틸리티 기반 Tailwind를 적용했다.
  2. 아직도 감이 안 오는가? Tailwind는 컴파일 시 기존에 정해진 기법만 해석이 가능한데(정적 데이터), 나는 props를 활용해 데이터를 전달받아 동적으로 사용하고 있다.
  3. 그렇다!! Tailwind는 컴파일 시 정해진 속성만 사용이 가능한데, 동적으로 사용하여 컴파일 시 동적으로 데이터를 읽지 못해 적용이 안 되는 현상이 발생한다.
  • 자 그러면 어떻게 코드를 고쳐야 할까?
    • 이 문제를 어떻게 하면 좋을지? 고민하던 도중 코드잇 심화과정을 진행하고 있는 주강사 님한테서 정보를 얻을 수 있었다.
    • 그건 바로 'clsx'라는 라이브러리이다!!!!
    • 'clsx'는 한마디로 정의하자면 조건에 따라 동적으로 클래스 이름을 생성하는 유틸리티 라이브러리라고 한다.
    • 그럼 한번 적용을 해보자!!
import clsx from "clsx";
import React from "react";

export default function Button({ children }) {
  return (
    <button
      className={clsx(
        `inline-block font-bold bg-blue-500 p-2`,
        children === "fadeIn" && "hover:animate-fadeIn",
        children === "slideIn" && "hover:animate-slideIn",
        children === "scaleUp" && "hover:animate-scaleUp",
        children === "rotate" && "hover:animate-rotate"
      )}
    >
      {children}
    </button>
  );
}

 

위 코드로 수정을 한 후

import Button from "@/components/Button";

export default function Home() {
  return (
    <div className="w-full mx-auto flex flex-col gap-6 p-12">
      <h1 className="font-bold text-4xl">hello world</h1>
      <Button children={"fadeIn"} />
      <Button children={"slideIn"} />
      <Button children={"scaleUp"} />
      <Button children={"rotate"} />
    </div>
  );
}

 

사용하는 곳에서 위 코드로 수정을 해보았다.

 

수정한 후 테스트를 해본 결과....

 

애니메이션이 잘 작동되는 것을 확인할 수 있다.

기쁜 마음으로 주강사 님한테 피드백을 받아보았다..

하지만 짧게나마 코드리뷰를 해주신 주강사 님 피드백!!

"코드 틀린 건 아니지만, 보통 인라인에 하지 않고 개별로 분류하면 더 좋겠다"는 피드백을 받아 바로 수정해 보았다."

import clsx from "clsx";
import React from "react";

const animations = {
  fadeIn: "hover:animate-fadeIn",
  slideIn: "hover:animate-slideIn",
  scaleUp: "hover:animate-scaleUp",
  rotate: "hover:animate-rotate",
};

export default function Button({ children }) {

  const animationClass = animations[children];

  return (
    <button
      className={clsx(
        `inline-block font-bold bg-blue-500 p-2`,
        animationClass // 여기서 조건에 맞는 애니메이션 클래스 적용
      )}
    >
      {children}
    </button>
  );
}
  • 위 코드처럼 animations라는 객체리터럴 형식의 변수를 하나 정의하여 수정 후 테스트 해본 결과 잘 작동되는 것을 확인하였다.

결론

  1. 개발 초기에는 스파게티 코드처럼 보일 수 있지만, 시간이 지나면서 코드를 리팩터링 하고 중복 코드를 개선하여 점차적으로 유지보수 가능한 구조로 변환해 나가야 한다는 것을 깨달았다.
  2. tailwind를 사용하면서 어떻게 동작되고 브라우저에 어느 시점에 적용되는지 알 수 있는 계기가 되었다.
  3. tailwind를 사용할 때 동적으로 속성을 적용해야 할 때 clsx라는 라이브러리를 알게 되었고, 바로 접목하여 문제를 해결하는 방법을 배웠다.
  4. 재사용성 컴포넌트를 학습하면서 '단단한 컴포넌트 부수기'라는 내용을 접할 수 있었다.
    1. 간략하게 학습한 내용을 설명을 하자면 컴포넌트 안에 prop으로 받는 속성이 늘어나면 안 좋다는 게 내 결론이다.
    2. 요구사항이 복잡해질수록 prop의 작명도 힘들어질 것이며, 파악하기도 힘들어진다.
      리액트는 상속보다는 조합!
  • 위 "단단한 컴포넌트 부수기"라는 주제는 좀 더 공부해야 하는 범위고, 디테일하게 알아야 하는 내용이라 다음 블로그 때 작성해 보겠다...!