Rules Hub
Coding Rules Library
Extract generic UI patterns into reusable components
Avoid implementing generic UI behaviors (like Modals, Drawers, or Tooltips) inline within feature components; extract them into reusable components.
Bad example
| 1 | const InvoiceTable = ({ invoices, isOpen, onClose }) => { |
| 2 | if (!isOpen) return null; |
| 3 |
|
| 4 | // BAD: Generic Modal logic (overlay, click propagation, scroll lock) |
| 5 | // is mixed directly with domain-specific invoice logic. |
| 6 | return ( |
| 7 | <div |
| 8 | className="modal-overlay" |
| 9 | onClick={onClose} |
| 10 | style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.5)' }} |
| 11 | > |
| 12 | <div |
| 13 | className="modal-content" |
| 14 | onClick={(e) => e.stopPropagation()} |
| 15 | > |
| 16 | <h2>Invoice History</h2> |
| 17 | {invoices.map(inv => <div key={inv.id}>{inv.amount}</div>)} |
| 18 | <button onClick={onClose}>Close</button> |
| 19 | </div> |
| 20 | </div> |
| 21 | ); |
| 22 | }; |
Explanation (EN)
The component mixes domain logic (displaying invoices) with generic UI mechanics (handling overlay clicks, stopping propagation, positioning). This makes the code repetitive if you need another modal elsewhere and clutters the component.
Objašnjenje (HR)
Komponenta miješa domensku logiku (prikaz faktura) s generičkom UI mehanikom (klikanje na overlay, zaustavljanje propagacije, pozicioniranje). To čini kod repetitivnim ako je potreban drugi modal negdje drugdje i zatrpava komponentu.
Good example
| 1 | // 1. Extract generic logic to a reusable component |
| 2 | const Modal = ({ isOpen, onClose, children }: ModalProps) => { |
| 3 | if (!isOpen) return null; |
| 4 |
|
| 5 | return ( |
| 6 | <div className="modal-overlay" onClick={onClose}> |
| 7 | <div className="modal-content" onClick={(e) => e.stopPropagation()}> |
| 8 | {children} |
| 9 | </div> |
| 10 | </div> |
| 11 | ); |
| 12 | }; |
| 13 |
|
| 14 | // 2. Consume it in the feature component |
| 15 | const InvoiceTable = ({ invoices, isOpen, onClose }) => { |
| 16 | return ( |
| 17 | <Modal isOpen={isOpen} onClose={onClose}> |
| 18 | <h2>Invoice History</h2> |
| 19 | {invoices.map(inv => <div key={inv.id}>{inv.amount}</div>)} |
| 20 | <button onClick={onClose}>Close</button> |
| 21 | </Modal> |
| 22 | ); |
| 23 | }; |
Explanation (EN)
The generic modal behavior is extracted into a dedicated `Modal` component that handles visibility, overlay clicks, and event propagation. The `InvoiceTable` component now focuses purely on rendering invoice data.
Objašnjenje (HR)
Generičko ponašanje modala izdvojeno je u zasebnu `Modal` komponentu koja upravlja vidljivošću, klikovima na pozadinu i propagacijom događaja. Komponenta `InvoiceTable` sada se fokusira isključivo na prikazivanje podataka o fakturama.