Rules Hub
Coding Rules Library
Prefer ReactNode props over render functions for static content
Define props as ReactNode or JSX.Element instead of render functions or Component types when the content does not rely on the component's internal state.
Bad example
| 1 | interface CardProps { |
| 2 | title: string; |
| 3 | // Unnecessary render function pattern if no data is passed back |
| 4 | renderFooter: () => JSX.Element; |
| 5 | // Or restrictive component type |
| 6 | Icon: React.ComponentType<{ size: number }>; |
| 7 | } |
| 8 |
|
| 9 | export const Card = ({ title, renderFooter, Icon }: CardProps) => ( |
| 10 | <div className="card"> |
| 11 | <Icon size={24} /> |
| 12 | <h1>{title}</h1> |
| 13 | <div className="footer">{renderFooter()}</div> |
| 14 | </div> |
| 15 | ); |
| 16 |
|
| 17 | // Usage requires wrapping in anonymous function |
| 18 | <Card |
| 19 | title="Profile" |
| 20 | Icon={UserIcon} |
| 21 | renderFooter={() => <button>Close</button>} |
| 22 | /> |
Explanation (EN)
Defining props as render functions (`() => JSX.Element`) or `ComponentType` creates unnecessary boilerplate at the usage site when no data needs to be passed from the child to the parent. It forces the consumer to wrap logic in functions or strictly match component interfaces.
Objašnjenje (HR)
Definiranje propova kao funkcija za renderiranje (`() => JSX.Element`) ili `ComponentType` stvara nepotreban 'boilerplate' pri korištenju kada nije potrebno prosljeđivati podatke od djeteta roditelju. To prisiljava potrošača da omata logiku u funkcije ili strogo prati sučelja komponenti.
Good example
| 1 | import { ReactNode } from 'react'; |
| 2 |
|
| 3 | interface CardProps { |
| 4 | title: string; |
| 5 | // Flexible: accepts any rendered element, string, or null |
| 6 | footer?: ReactNode; |
| 7 | icon?: ReactNode; |
| 8 | } |
| 9 |
|
| 10 | export const Card = ({ title, footer, icon }: CardProps) => ( |
| 11 | <div className="card"> |
| 12 | {icon} |
| 13 | <h1>{title}</h1> |
| 14 | {footer && <div className="footer">{footer}</div>} |
| 15 | </div> |
| 16 | ); |
| 17 |
|
| 18 | // Usage is direct, cleaner, and more flexible |
| 19 | <Card |
| 20 | title="Profile" |
| 21 | icon={<UserIcon size={24} />} |
| 22 | footer={<button>Close</button>} |
| 23 | /> |
Explanation (EN)
Using `ReactNode` (or `JSX.Element`) allows the consumer to pass anything that React can render directly (elements, strings, null). It simplifies the usage syntax by removing the need for arrow functions and allows pre-configured components to be passed easily.
Objašnjenje (HR)
Korištenje `ReactNode` (ili `JSX.Element`) omogućuje potrošaču da izravno proslijedi bilo što što React može renderirati (elemente, stringove, null). To pojednostavljuje sintaksu uklanjanjem potrebe za 'arrow' funkcijama i omogućuje lako prosljeđivanje unaprijed konfiguriranih komponenti.
Notes (EN)
Only use render props (functions) if you need to pass internal state from the child component back to the injected content (e.g., renderItem={(item) => ...}).
Bilješke (HR)
Koristite 'render props' (funkcije) samo ako trebate proslijediti interno stanje iz djeteta u ubrizgani sadržaj (npr. renderItem={(item) => ...}).