Tailwind를 사용하여 재사용 가능한 React 구성 요소 빌드

게시 됨: 2022-03-10
빠른 요약 ↬ Tailwind는 웹 개발자에게 낮은 수준의 클래스 이름을 제공하는 널리 사용되는 유틸리티 우선 CSS 프레임워크입니다. JavaScript가 없으며 React, Vue, Angular, Ember 등과 같은 기존 프레임워크와 잘 작동합니다. 이는 긍정적이지만 새로운 개발자가 자신의 애플리케이션에 Tailwind를 통합하는 방법을 이해하는 데 혼란을 줄 수 있습니다. 이 기사에서는 Tailwind를 사용하여 재사용 가능한 React 구성 요소를 빌드하는 방법을 살펴보겠습니다.

이 게시물에서는 다른 구성 요소에 대한 멋진 인터페이스를 노출하면서 내부적으로 Tailwind를 활용하는 재사용 가능한 React 구성 요소를 구축할 수 있는 여러 가지 방법을 살펴보겠습니다. 이렇게 하면 긴 클래스 이름 목록에서 읽기 및 유지 관리가 더 쉬운 시맨틱 소품으로 이동하여 코드를 개선할 수 있습니다.

이 게시물을 잘 이해하려면 React로 작업해야 합니다.

Tailwind는 개발자가 맞춤형 디자인을 구축하는 데 도움이 되는 저수준 유틸리티 클래스를 제공하는 매우 인기 있는 CSS 프레임워크입니다. 두 가지 문제를 정말 잘 해결했기 때문에 지난 몇 년 동안 인기가 높아졌습니다.

  1. Tailwind를 사용하면 일치하는 CSS 선택기를 찾기 위해 스타일시트를 뒤지지 않고 HTML을 반복적으로 쉽게 변경할 수 있습니다.
  2. Tailwind에는 정상적인 규칙과 기본값이 있습니다. 이것은 사람들이 CSS를 처음부터 작성하지 않고도 쉽게 시작할 수 있도록 합니다.

포괄적인 문서를 추가하면 Tailwind가 인기 있는 이유가 됩니다.

이러한 방법은 다음과 같은 코드를 변환하는 데 도움이 됩니다.

 <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"> Enable </button>

다음과 같은 코드를 작성하려면:

 <Button size="sm" textColor="white" bgColor="blue-500"> Enable </Button>

두 스니펫의 차이점은 첫 번째 스니펫에서는 표준 HTML 버튼 태그를 사용하고 두 번째 스니펫은 <Button> 구성요소를 사용했다는 것입니다. <Button> 구성 요소는 재사용성을 위해 구축되었으며 더 나은 의미 체계를 가지고 있기 때문에 더 읽기 쉽습니다. 긴 클래스 이름 목록 대신 속성을 사용하여 size , textColorbgColor 와 같은 다양한 속성을 설정합니다.

시작하자.

점프 후 더! 아래에서 계속 읽기 ↓

방법 1: Classnames 모듈로 클래스 제어하기

Tailwind를 React 애플리케이션에 적용하는 간단한 방법은 클래스 이름을 수용하고 프로그래밍 방식으로 전환하는 것입니다.

classnames npm 모듈을 사용하면 React에서 클래스를 쉽게 토글할 수 있습니다. 이것을 사용하는 방법을 보여주기 위해 React 애플리케이션에 <Button> 구성 요소가 있는 사용 사례를 살펴보겠습니다.

 // This could be hard to read. <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">Enable</button> // This is more conventional React. <Button size="sm" textColor="white" bgColor="blue-500">Enable</Button>

<Button> 컴포넌트를 사용하는 사람들이 size , textColorbgColor 와 같은 React props를 사용할 수 있도록 Tailwind 클래스를 분리하는 방법을 살펴보겠습니다.

  1. bgColortextColor 와 같은 소품을 클래스 이름 문자열 템플릿에 직접 전달합니다.
  2. 객체를 사용하여 클래스 이름을 프로그래밍 방식으로 전환합니다( size 소품에서 수행한 것처럼).

아래 예제 코드에서 두 가지 접근 방식을 모두 살펴보겠습니다.

 // Button.jsx import classnames from 'classnames'; function Button ({size, bgColor, textColor, children}) { return ( <button className={classnames("bg-${bgColor} text-${textColor} font-bold py-2 px-4 rounded", { "text-xs": size === 'sm' "text-xl": size === 'lg', })}> {children} </button> ) }; export default Button;

위의 코드에서 다음 소품을 사용하는 Button 구성 요소를 정의합니다.

  • size
    버튼의 크기를 정의하고 Tailwind 클래스 text-xs 또는 text-xl 을 적용합니다.
  • bgColor
    버튼의 배경색을 정의하고 Tailwind bg-* 클래스를 적용합니다.
  • textColor
    버튼의 텍스트 색상을 정의하고 Tailwind text-* classes 를 적용합니다.
  • children
    모든 하위 구성 요소는 여기를 통해 전달됩니다. 일반적으로 <Button> 안에 텍스트가 포함됩니다.

Button.jsx 를 정의하여 이제 클래스 이름 대신 React props를 가져오고 사용할 수 있습니다. 이렇게 하면 코드를 더 쉽게 읽고 재사용할 수 있습니다.

 import Button from './Button'; <Button size="sm" textColor="white" bgColor="blue-500">Enable</Button>

대화형 구성 요소에 클래스 이름 사용

버튼은 매우 간단한 사용 사례입니다. 더 복잡한 것은 어떻습니까? 글쎄, 이것을 더 발전시켜 대화형 구성 요소를 만들 수 있습니다.

예를 들어 Tailwind를 사용하여 만든 드롭다운을 살펴보겠습니다.


Tailwind 및 클래스 이름 전환을 사용하여 구축된 대화형 드롭다운입니다.

이 예에서는 Tailwind CSS 클래스 이름을 사용하여 HTML 구성 요소를 생성하지만 다음과 같은 React 구성 요소를 노출합니다.

 <Dropdown options={\["Edit", "Duplicate", "Archive", "Move", "Delete"\]} onOptionSelect={(option) => { console.log("Selected Option", option)} } />

위의 코드를 보면 Tailwind 클래스가 없음을 알 수 있습니다. 그것들은 모두 <Dropdown/> 의 구현 코드 안에 숨겨져 있습니다. 이 Dropdown 구성 요소의 사용자는 option 을 클릭할 때 options 목록과 클릭 핸들러 onOptionSelect 를 제공하기만 하면 됩니다.

Tailwind를 사용하여 이 구성 요소를 구축하는 방법을 살펴보겠습니다.

관련 없는 코드 중 일부를 제거하면 여기에 논리의 핵심이 있습니다. 전체 예제를 보려면 이 Codepen을 볼 수 있습니다.

 import classNames from 'classnames'; function Dropdown({ options, onOptionSelect }) { // Keep track of whether the dropdown is open or not. const [isActive, setActive] = useState(false); const buttonClasses = `inline-flex justify-center w-full rounded-md border border-gray-300 px-4 py-2 bg-white text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-blue-500 active:text-gray-200 transition ease-in-out duration-150`; return ( // Toggle the dropdown if the button is clicked <button onClick={() => setActive(!isActive)} className={buttonClasses}> Options </button> // Use the classnames module to toggle the Tailwind .block and .hidden classes <div class={classNames("origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg", { block: isActive, hidden: !isActive })}> // List items are rendered here. {options.map((option) => <div key={option} onClick={(e) => onOptionSelect(option)}>{option}</div>)} </div> ) } export default Dropdown;

드롭다운은 .hidden.block 클래스를 사용하여 선택적으로 표시하거나 숨김으로써 대화형으로 만들어집니다. <button> 을 누를 때마다 isActive 상태를 토글하는 onClick 핸들러를 시작합니다. 버튼이 활성화되면( isActive === true ) block 클래스를 설정합니다. 그렇지 않으면 hidden 클래스를 설정합니다. 이는 표시 동작을 토글하기 위한 Tailwind 클래스입니다.

요약하면 classnames 모듈은 Tailwind의 클래스 이름을 프로그래밍 방식으로 제어하는 ​​간단하고 효과적인 방법입니다. 로직을 React props로 쉽게 분리할 수 있어 구성 요소를 더 쉽게 재사용할 수 있습니다. 단순하고 대화형 구성 요소에 대해 작동합니다.

방법 2: 상수를 사용하여 디자인 시스템 정의하기

Tailwind와 React를 함께 사용하는 또 다른 방법은 상수를 사용하고 props를 특정 상수에 매핑하는 것입니다. 이것은 설계 시스템을 구축하는 데 효과적입니다. 예를 들어 설명하겠습니다.

디자인 시스템을 나열하는 theme.js 파일로 시작하십시오.

 // theme.js (you can call it whatever you want) export const ButtonType = { primary: "bg-blue-500 hover:bg-blue-700 text-white font-bold rounded", secondary: "bg-blue-500 hover:bg-blue-700 text-white font-bold rounded", basic: "bg-white hover:bg-gray-700 text-gray-700 font-bold rounded", delete: "bg-red-300 hover:bg-red-500 text-white font-bold rounded" }; export const ButtonSize = { sm: "py-2 px-4 text-xs", lg: "py-3 px-6 text-lg" }

이 경우 두 가지 상수 집합이 있습니다.

  • ButtonType 은 앱에서 버튼의 스타일을 지정하는 방법을 정의합니다.
  • ButtonSizes 는 앱의 버튼 크기를 정의합니다.

이제 <Button> 구성 요소를 작성해 보겠습니다.

 import {ButtonType, ButtonSize} from './theme'; function Button({size, type, children}) { // This can be improved. I'm keeping it simple here by joining two strings. const classNames = ButtonType[type] + " " + ButtonSize[size]; return ( <button className={classNames}>{children}</button> ) } export default Button;

ButtonTypeButtonSize 상수를 사용하여 클래스 이름 목록을 만듭니다. 이것은 <Button> 의 인터페이스를 훨씬 더 멋지게 만듭니다. 클래스 이름 문자열에 모든 것을 넣는 대신 sizetype 소품을 사용할 수 있습니다.

 // Cleaner and well defined props. <Button size="xs" type="primary">Enable</Button>

이전 접근 방식과 비교:

 // Exposing class names <button className="py-2 px-4 text-xs bg-blue-500 hover:bg-blue-700 text-white font-bold rounded">Enable</button>

애플리케이션에서 버튼이 어떻게 보이는지 재정의해야 하는 경우 theme.js 파일을 편집하기만 하면 앱의 모든 버튼이 자동으로 업데이트됩니다. 이것은 다양한 구성 요소에서 클래스 이름을 검색하는 것보다 쉬울 수 있습니다.

방법 3: @apply 로 유틸리티 구성

React 구성 요소의 가독성을 향상시키는 세 번째 방법은 CSS와 PostCSS에서 사용 가능한 @apply 패턴을 사용하여 반복되는 클래스를 추출하는 것입니다. 이 패턴은 스타일시트와 후처리기를 사용합니다.

예제를 통해 이것이 어떻게 작동하는지 보여줍시다. 기본 및 보조 버튼이 있는 버튼 그룹이 있다고 가정합니다.

기본 버튼과 보조 버튼으로 구성된 버튼 그룹
기본 및 보조 버튼으로 구성된 버튼 그룹입니다. (큰 미리보기)
 <button className="py-2 px-4 mr-4 text-xs bg-blue-500 hover:bg-blue-700 text-white font-bold rounded">Update Now</button> <button className="py-2 px-4 text-xs mr-4 hover:bg-gray-100 text-gray-700 border-gray-300 border font-bold rounded">Later</button>

@apply 패턴을 사용하여 이 HTML을 다음과 같이 작성할 수 있습니다.

 <button className="btn btn-primary btn-xs">Update Now</button> <button className="btn btn-secondary btn-xs">Later</button>

그런 다음 React에 채택되어 다음과 같이 될 수 있습니다.

 import classnames from "classnames"; function Button ({size, type, children}) { const bSize = "btn-" + size; const bType = "btn-" + type; return ( <button className={classnames("btn", bSize, bType)}>{children}</button> ) } Button.propTypes = { size: PropTypes.oneOf(['xs, xl']), type: PropTypes.oneOf(['primary', 'secondary']) }; // Using the Button component. <Button type="primary" size="xs">Update Now</Button> <Button type="secondary" size="xs">Later</Button>

.btn , .btn-primary 등과 같은 BEM 스타일 클래스 이름을 만드는 방법은 다음과 같습니다. button.css 파일을 생성하여 시작합니다.

 /\* button.css \*/ @tailwind base; @tailwind components; .btn { @apply py-2 px-4 mr-4 font-bold rounded; } .btn-primary { @apply bg-blue-500 hover:bg-blue-700 text-white; } .btn-secondary { @apply hover:bg-gray-700 text-gray-700 border-gray-300 border; } .btn-xs { @apply text-xs; } .btn-xl { @apply text-xl; } @tailwind utilities;

위의 코드는 실제 CSS가 아니지만 PostCSS에 의해 컴파일됩니다. JavaScript 프로젝트에 PostCSS 및 Tailwind를 설정하는 방법을 보여주는 GitHub 리포지토리가 있습니다.

여기에서 설정하는 방법을 보여주는 짧은 비디오도 있습니다.

@apply 사용의 단점

Tailwind 유틸리티 클래스를 더 높은 수준의 CSS 클래스로 추출하는 개념은 이치에 맞는 것처럼 보이지만 알고 있어야 하는 몇 가지 단점이 있습니다. 다른 예를 들어 이를 강조해 보겠습니다.

먼저 이러한 클래스 이름을 추출하여 일부 정보를 잃게 됩니다. 예를 들어 .btn-primary 는 이미 .btn 이 적용된 구성 요소에 추가되어야 합니다. 또한 .btn-primary.btn-secondary 는 함께 적용할 수 없습니다. 이 정보는 클래스만 보면 알 수 없습니다.

이 구성 요소가 더 복잡한 경우 클래스 간의 부모-자식 관계도 이해해야 합니다. 어떤 면에서 이것은 Tailwind가 해결하도록 설계된 문제이며 @apply 를 사용하여 다른 방식으로 문제를 다시 가져오고 있습니다.

다음은 Tailwind의 제작자인 Adam Wathan이 @apply 사용의 장단점에 대해 설명하는 동영상입니다.

요약

이 기사에서는 Tailwind를 React 애플리케이션에 통합하여 재사용 가능한 구성 요소를 구축하는 세 가지 방법을 살펴보았습니다. 이러한 메서드는 props 를 사용하여 더 깔끔한 인터페이스를 가진 React 구성 요소를 빌드하는 데 도움이 됩니다.

  1. 클래스 이름 모듈을 사용하여 프로그래밍 방식으로 클래스를 토글합니다.
  2. 구성 요소 상태당 클래스 목록을 정의하는 상수 파일을 정의합니다.
  3. @apply 를 사용하여 더 높은 수준의 CSS 클래스를 추출합니다.

질문이 있으면 Twitter @tilomitra로 메시지를 보내주십시오.

SmashingMag에 대한 권장 읽기 :

  • React 프로젝트에서 Tailwind CSS 설정하기
  • React로 정렬 가능한 테이블 만들기
  • Firefox의 새롭고 실험적인 CSS DevTools 가이드
  • 자신만의 확장 및 축소 콘텐츠 패널 만들기