Tailwindを使用した再利用可能なReactコンポーネントの構築

公開: 2022-03-10
簡単な要約↬Tailwindは、Web開発者に低レベルのクラス名を提供する人気のあるユーティリティファーストのCSSフレームワークです。 JavaScriptはなく、React、Vue、Angular、Emberなどの既存のフレームワークでうまく機能します。 これは前向きなことですが、新しい開発者がTailwindをアプリケーションに統合する方法を理解するのは混乱を招く可能性があります。 この記事では、Tailwindを使用して再利用可能なReactコンポーネントを構築する方法を探ります。

この投稿では、他のコンポーネントへの優れたインターフェイスを公開しながら、内部でTailwindを活用する再利用可能なReactコンポーネントを構築するためのいくつかの異なる方法を見ていきます。 これにより、クラス名の長いリストから、読みやすく保守しやすいセマンティックプロップに移行することで、コードが改善されます。

この投稿をよく理解するには、Reactを使用している必要があります。

Tailwindは非常に人気のあるCSSフレームワークであり、開発者がカスタムデザインを作成するのに役立つ低レベルのユーティリティクラスを提供します。 2つの問題を非常にうまく解決するため、ここ数年で人気が高まっています。

  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ボタンタグを使用し、2番目のスニペットでは<Button>コンポーネントを使用したことです。 <Button>コンポーネントは再利用性のために構築されており、セマンティクスが優れているため読みやすくなっています。 クラス名の長いリストの代わりに、プロパティを使用して、 sizetextColorbgColorなどのさまざまな属性を設定します。

始めましょう。

ジャンプした後もっと! 以下を読み続けてください↓

方法1:クラス名モジュールを使用してクラスを制御する

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>コンポーネントを使用する人々がsizetextColorbgColorなどのReact小道具を使用できるようにTailwindクラスを分離する方法を見てみましょう。

  1. bgColortextColorなどの小道具をクラス名文字列テンプレートに直接渡します。
  2. オブジェクトを使用して、プログラムでクラス名を切り替えます( size propで行ったように)

以下のサンプルコードでは、両方のアプローチを見ていきます。

 // 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
    ボタンの背景色を定義し、 bg-*クラスを適用します。
  • textColor
    ボタンのテキストの色を定義し、Tailwind text-* classesを適用します。
  • children
    サブコンポーネントはすべてここを通過します。 通常、 <Button>内のテキストが含まれます。

Button.jsxを定義することで、これをインポートして、クラス名の代わりにReactプロップを使用できるようになりました。 これにより、コードが読みやすくなり、再利用しやすくなります。

 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コンポーネントのユーザーは、 optionsのリストと、 optionがクリックされたときに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プロップに分離しやすくなり、コンポーネントの再利用が容易になります。 シンプルでインタラクティブなコンポーネントで機能します。

方法2:定数を使用して設計システムを定義する

TailwindとReactを一緒に使用する別の方法は、定数を使用し、小道具を特定の定数にマッピングすることです。 これは、設計システムの構築に効果的です。 例を挙げてデモンストレーションしましょう。

デザインシステムを一覧表示する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" }

この場合、2セットの定数があります。

  • 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;

ButtonType定数とButtonSize定数を使用して、クラス名のリストを作成します。 これにより、 <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コンポーネントの読みやすさを向上させる3番目の方法は、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を同時に適用することはできません。 この情報は、クラスを見ただけではわかりません。

このコンポーネントがもっと複​​雑な場合は、クラス間の親子関係も理解する必要があります。 ある意味、これは@applyが解決するように設計された問題であり、@ applyを使用することで、別の方法で問題を元に戻しています。

これは、Tailwindの作成者であるAdamWathanが@applyを使用することの長所と短所を詳しく説明しているビデオです。

概要

この記事では、TailwindをReactアプリケーションに統合して再利用可能なコンポーネントを構築する3つの方法について説明しました。 これらのメソッドは、 propsを使用してよりクリーンなインターフェースを持つReactコンポーネントを構築するのに役立ちます。

  1. classnamesモジュールを使用して、プログラムでクラスを切り替えます。
  2. コンポーネントの状態ごとにクラスのリストを定義する定数ファイルを定義します。
  3. @applyを使用して、高レベルのCSSクラスを抽出します。

ご不明な点がございましたら、Twitterの@tilomitraでメッセージを送ってください。

SmashingMagの推奨読書

  • ReactプロジェクトでのTailwindCSSの設定
  • Reactでソート可能なテーブルを作成する
  • Firefoxの新しい実験的なCSSDevToolsのガイド
  • 独自の拡張および縮小コンテンツパネルを作成する