Render Function
Problem
Components require static markup that can’t adapt to different data structures or render variations. You end up creating separate components for minor rendering differences, or embedding complex conditional logic directly in templates that becomes difficult to read and maintain.
Solution
Use functions to render components based on props and state rather than templates. This provides the full power of JavaScript for conditional logic and transformations.
Example
This example demonstrates a list component that accepts a custom render function, allowing consumers to control how each item is displayed without modifying the component.
// Framework-agnostic render function pattern
class List extends HTMLElement {
set items(value) {
this._items = value;
this.render();
}
// Accept custom render function for flexibility
set renderItem(fn) {
this._renderItem = fn;
this.render();
}
render() {
if (!this._items || !this._renderItem) return;
// Use provided render function for each item
const listItems = this._items
.map(item => `<li>${this._renderItem(item)}</li>`)
.join('');
this.innerHTML = `<ul>${listItems}</ul>`;
}
}
// Usage - consumers control how items render
const list = document.querySelector('list-component');
list.items = users;
list.renderItem = (user) => `<span>${user.name}</span>`;
Benefits
- Provides full JavaScript flexibility for complex rendering logic.
- Makes components highly reusable by accepting custom render functions.
- Enables powerful composition patterns like render props.
- Simplifies complex conditional rendering compared to template syntax.
Tradeoffs
- Can make component structure less clear than declarative templates.
- May require more JavaScript knowledge than template-based approaches.
- Can lead to verbose code when simple templating would suffice.
- Makes JSX less readable when render functions are deeply nested.