การสร้างส่วนประกอบ React แบบใช้ซ้ำได้โดยใช้ Tailwind
เผยแพร่แล้ว: 2022-03-10ในโพสต์นี้ เราจะพูดถึงวิธีต่างๆ มากมายที่คุณสามารถสร้างส่วนประกอบ React ที่นำกลับมาใช้ใหม่ได้ ซึ่งใช้ประโยชน์จาก Tailwind ภายใต้ประทุน ในขณะที่เปิดเผยอินเทอร์เฟซที่ดีให้กับส่วนประกอบอื่นๆ วิธีนี้จะช่วยปรับปรุงโค้ดของคุณโดยการย้ายจากรายชื่อคลาสยาวๆ ไปเป็นอุปกรณ์ประกอบฉากที่อ่านและบำรุงรักษาได้ง่ายขึ้น
คุณจะต้องทำงานกับ React เพื่อทำความเข้าใจโพสต์นี้ให้ดี
Tailwind คือเฟรมเวิร์ก CSS ยอดนิยมที่มีคลาสยูทิลิตี้ระดับต่ำ เพื่อช่วยนักพัฒนาสร้างการออกแบบที่กำหนดเอง ได้รับความนิยมเพิ่มขึ้นในช่วงไม่กี่ปีที่ผ่านมา เนื่องจากสามารถแก้ปัญหาสองประการได้ดีมาก:
- Tailwind ช่วยให้ทำการเปลี่ยนแปลงซ้ำๆ กับ HTML ได้อย่างง่ายดายโดยไม่ต้องค้นหาสไตล์ชีตเพื่อค้นหาตัวเลือก CSS ที่ตรงกัน
- 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
, textColor
และ bgColor
มาเริ่มกันเลย.
วิธีที่ 1: การควบคุมคลาสด้วยโมดูลชื่อคลาส
วิธีง่ายๆ ในการปรับ Tailwind ให้เป็นแอปพลิเคชัน React คือการยอมรับชื่อคลาสและสลับชื่อคลาสโดยทางโปรแกรม
โมดูลชื่อคลาส npm ทำให้ง่ายต่อการสลับคลาสใน React เพื่อสาธิตวิธีการใช้สิ่งนี้ ลองใช้กรณีที่คุณมีส่วนประกอบ <Button>
ในแอปพลิเคชัน React ของคุณ
// 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>
มาดูวิธีแยกคลาส Tailwind เพื่อให้ผู้ใช้คอมโพเนนต์ <Button>
สามารถใช้ React props เช่น size
, textColor
และ bgColor
- ส่งอุปกรณ์ประกอบฉาก เช่น
bgColor
และtextColor
ไปยังเทมเพลตสตริงชื่อคลาสโดยตรง - ใช้อ็อบเจ็กต์เพื่อเปลี่ยนชื่อคลาสโดยทางโปรแกรม (ตามที่เราทำกับเสา
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
กำหนดขนาดของปุ่มและใช้คลาส Tailwindtext-xs
หรือtext-xl
-
bgColor
กำหนดสีพื้นหลังของปุ่มและใช้คลาส Tailwindbg-*
-
textColor
กำหนดสีข้อความของปุ่มและใช้text-* classes
-
children
ส่วนประกอบย่อยใดๆ จะถูกส่งผ่านที่นี่ โดยปกติจะมีข้อความอยู่ภายใน<Button>
ด้วยการกำหนด Button.jsx
ตอนนี้เราสามารถนำเข้าและใช้ React props แทนชื่อคลาสได้ ทำให้โค้ดของเราอ่านและนำกลับมาใช้ใหม่ได้ง่ายขึ้น
import Button from './Button'; <Button size="sm" textColor="white" bgColor="blue-500">Enable</Button>
การใช้ชื่อคลาสสำหรับส่วนประกอบแบบโต้ตอบ
ปุ่มเป็นกรณีใช้งานที่ง่ายมาก แล้วอะไรที่ซับซ้อนกว่านั้นล่ะ? คุณสามารถใช้สิ่งนี้เพิ่มเติมเพื่อสร้างองค์ประกอบแบบโต้ตอบได้
ตัวอย่างเช่น มาดูดรอปดาวน์ที่สร้างโดยใช้ Tailwind
ดรอปดาวน์แบบอินเทอร์แอกทีฟที่สร้างขึ้นโดยใช้ Tailwind และการสลับชื่อคลาส
สำหรับตัวอย่างนี้ เราสร้างองค์ประกอบ HTML โดยใช้ชื่อคลาส Tailwind CSS แต่เราเปิดเผยองค์ประกอบ React ที่มีลักษณะดังนี้:
<Dropdown options={\["Edit", "Duplicate", "Archive", "Move", "Delete"\]} onOptionSelect={(option) => { console.log("Selected Option", option)} } />
เมื่อดูโค้ดด้านบน คุณจะสังเกตเห็นว่าเราไม่มีคลาส Tailwind ทั้งหมดถูกซ่อนอยู่ภายในโค้ดการใช้งานของ <Dropdown/>
ผู้ใช้องค์ประกอบ Dropdown
ต้องระบุรายการ options
และตัวจัดการการคลิก onOptionSelect
เมื่อ option
เรามาดูกันว่าจะสร้างคอมโพเนนต์นี้โดยใช้ 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>
เราจะเริ่มตัวจัดการ onClick
ที่สลับสถานะ isActive
หากปุ่มทำงานอยู่ ( isActive === true
) เราจะตั้งค่าคลาส block
มิฉะนั้นเราจะตั้งค่าคลาสที่ hidden
ซึ่งเป็นทั้งคลาสของ Tailwind สำหรับการสลับลักษณะการแสดงผล
โดยสรุป โมดูลชื่อคลาสเป็นวิธีที่ง่ายและมีประสิทธิภาพในการควบคุมชื่อคลาสโดยทางโปรแกรมสำหรับ Tailwind ทำให้ง่ายต่อการแยกตรรกะออกจาก React props ซึ่งทำให้ส่วนประกอบของคุณนำกลับมาใช้ใหม่ได้ง่ายขึ้น ใช้งานได้กับส่วนประกอบที่เรียบง่ายและโต้ตอบได้
วิธีที่ 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" }
ในกรณีนี้ เรามีค่าคงที่สองชุด:
-
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>
ของเราดีขึ้นมาก ช่วยให้เราใช้ size
และ type
อุปกรณ์ประกอบฉากแทนการใส่ทุกอย่างในสตริงชื่อคลาส
// 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 และรูปแบบ @apply
ที่มีอยู่ใน PostCSS เพื่อแยกคลาสที่ซ้ำกัน รูปแบบนี้เกี่ยวข้องกับการใช้สไตล์ชีตและตัวประมวลผลภายหลัง
มาสาธิตวิธีการทำงานผ่านตัวอย่างกัน สมมติว่าคุณมีกลุ่มปุ่มที่มีปุ่มหลักและปุ่มรอง
<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>
ต่อไปนี้คือวิธีสร้างชื่อคลาสสไตล์ BEM เช่น .btn
, .btn-primary
และอื่นๆ เริ่มต้นด้วยการสร้างไฟล์ 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 มีที่เก็บ GitHub ที่นี่ ซึ่งจะแสดงวิธีตั้งค่า PostCSS และ Tailwind สำหรับโปรเจ็กต์ JavaScript
นอกจากนี้ยังมีวิดีโอสั้น ๆ ที่แสดงวิธีตั้งค่าที่นี่
ข้อเสียของการใช้ @apply
แนวคิดในการแยกคลาสยูทิลิตี้ Tailwind ออกเป็นคลาส CSS ระดับสูงดูเหมือนจะสมเหตุสมผล แต่มีข้อเสียบางประการที่คุณควรทราบ มาเน้นสิ่งเหล่านี้ด้วยตัวอย่างอื่น
อันดับแรก การแยกชื่อคลาสเหล่านี้ออก เราจะสูญเสียข้อมูลบางส่วน ตัวอย่างเช่น เราต้องระวังว่าจะต้องเพิ่ม .btn-primary
ลงในส่วนประกอบที่มี .btn
นำไปใช้กับมันอยู่แล้ว นอกจากนี้ .btn-primary
และ .btn-secondary
ยังใช้ร่วมกันไม่ได้ ข้อมูลนี้ไม่ปรากฏชัดเมื่อดูจากชั้นเรียน
ถ้าองค์ประกอบนี้เป็นสิ่งที่ซับซ้อนกว่านั้น คุณจะต้องเข้าใจความสัมพันธ์หลักและรองระหว่างชั้นเรียนด้วย ในแง่หนึ่ง นี่คือปัญหาที่ Tailwind ออกแบบมาเพื่อแก้ไข และด้วยการใช้ @apply
เรากำลังนำปัญหากลับมาด้วยวิธีที่ต่างออกไป
นี่คือวิดีโอที่ Adam Wathan ผู้สร้าง Tailwind เจาะลึกข้อดีข้อเสียของการใช้ @apply
สรุป
ในบทความนี้ เราได้พิจารณาสามวิธีในการผสานรวม Tailwind เข้ากับแอปพลิเคชัน React เพื่อสร้างส่วนประกอบที่ใช้ซ้ำได้ วิธีการเหล่านี้ช่วยให้คุณสร้างส่วนประกอบ React ที่มีอินเทอร์เฟซที่สะอาดขึ้นโดยใช้ props
- ใช้โมดูลชื่อคลาสเพื่อสลับคลาสโดยทางโปรแกรม
- กำหนดไฟล์ค่าคงที่ที่คุณกำหนดรายการของคลาสต่อสถานะคอมโพเนนต์
- ใช้
@apply
เพื่อแยกคลาส CSS ระดับสูง
หากคุณมีคำถามใด ๆ ส่งข้อความบน Twitter ที่ @tilomitra
การอ่านที่แนะนำ บน SmashingMag:
- การตั้งค่า Tailwind CSS ในโครงการตอบสนอง
- การสร้างตารางที่จัดเรียงได้ด้วย React
- คำแนะนำเกี่ยวกับ CSS DevTools ใหม่และทดลองใน Firefox
- สร้างแผงเนื้อหาที่ขยายและทำสัญญาของคุณเอง