Advanced Components in Coherent.js
November 17, 2025 ยท View on GitHub
This guide covers advanced component patterns, optimization techniques, and complex use cases in Coherent.js. Learn how to build sophisticated, reusable, and performant components.
๐ Higher-Order Components (HOCs)
Basic HOC Pattern
Higher-Order Components are functions that take a component and return a new component with additional functionality:
const withLoading = (WrappedComponent) => {
return withState({ isLoading: false })(({ state, stateUtils, ...props }) => {
const { setState } = stateUtils;
if (state.isLoading) {
return {
div: {
className: 'loading-container',
children: [
{ div: { className: 'spinner' } },
{ p: { text: 'Loading...' } }
]
}
};
}
return WrappedComponent({
...props,
setLoading: (isLoading) => setState({ isLoading })
});
});
};
// Usage
const DataComponent = ({ data, setLoading }) => ({
div: {
children: [
{ h2: { text: 'Data Display' } },
{
button: {
text: 'Load Data',
onclick: async () => {
setLoading(true);
await fetchData();
setLoading(false);
}
}
}
]
}
});
const LoadingDataComponent = withLoading(DataComponent);
Composable HOCs
Chain multiple HOCs together for complex functionality:
const withAuth = (WrappedComponent) => {
return withState({ user: null })(({ state, stateUtils, ...props }) => {
if (!state.user) {
return {
div: {
className: 'auth-required',
children: [
{ h2: { text: 'Authentication Required' } },
{ button: { text: 'Login', onclick: () => showLogin() } }
]
}
};
}
return WrappedComponent({ ...props, user: state.user });
});
};
const withErrorBoundary = (WrappedComponent) => {
return withState({ hasError: false, error: null })(({ state, stateUtils, ...props }) => {
const { setState } = stateUtils;
if (state.hasError) {
return {
div: {
className: 'error-boundary',
children: [
{ h2: { text: 'Something went wrong' } },
{ p: { text: state.error?.message } },
{
button: {
text: 'Try Again',
onclick: () => setState({ hasError: false, error: null })
}
}
]
}
};
}
try {
return WrappedComponent({
...props,
onError: (error) => setState({ hasError: true, error })
});
} catch (error) {
setState({ hasError: true, error });
return { div: { text: 'Error occurred' } };
}
});
};
// Compose multiple HOCs
const EnhancedComponent = withAuth(withErrorBoundary(withLoading(DataComponent)));
Context Provider HOC
Create context-like functionality with HOCs:
const withTheme = (WrappedComponent) => {
return withState({
theme: 'light',
colors: {
primary: '#007bff',
secondary: '#6c757d',
background: '#ffffff'
}
})(({ state, stateUtils, ...props }) => {
const { setState } = stateUtils;
const toggleTheme = () => {
const newTheme = state.theme === 'light' ? 'dark' : 'light';
const newColors = newTheme === 'dark' ? {
primary: '#0d6efd',
secondary: '#adb5bd',
background: '#212529'
} : {
primary: '#007bff',
secondary: '#6c757d',
background: '#ffffff'
};
setState({ theme: newTheme, colors: newColors });
};
return WrappedComponent({
...props,
theme: state.theme,
colors: state.colors,
toggleTheme
});
});
};
๐ Component Composition Patterns
Render Props Pattern
Pass rendering logic as props:
const DataFetcher = ({ url, children }) => {
return withState({
data: null,
loading: false,
error: null
})(({ state, stateUtils }) => {
const { setState } = stateUtils;
const fetchData = async () => {
setState({ loading: true, error: null });
try {
const response = await fetch(url);
const data = await response.json();
setState({ data, loading: false });
} catch (error) {
setState({ error: error.message, loading: false });
}
};
if (typeof children === 'function') {
return children({
data: state.data,
loading: state.loading,
error: state.error,
refetch: fetchData
});
}
return { div: { text: 'No render function provided' } };
});
};
// Usage
const App = () => ({
div: {
children: [
DataFetcher({
url: '/api/users',
children: ({ data, loading, error, refetch }) => {
if (loading) return { div: { text: 'Loading...' } };
if (error) return { div: { text: `Error: ${error}` } };
return {
div: {
children: [
{ h2: { text: 'Users' } },
{ button: { text: 'Refresh', onclick: refetch } },
data ? {
ul: {
children: data.map(user => ({
li: { key: user.id, text: user.name }
}))
}
} : null
].filter(Boolean)
}
};
}
})
]
}
});
Compound Components
Create components that work together:
const Tabs = withState({ activeTab: 0 })(({ state, stateUtils, children }) => {
const { setState } = stateUtils;
const childrenArray = Array.isArray(children) ? children : [children];
const tabPanels = childrenArray.filter(child => child.type === 'TabPanel');
const tabLabels = childrenArray.filter(child => child.type === 'TabList');
return {
div: {
className: 'tabs-container',
children: [
// Tab navigation
{
ul: {
className: 'tab-nav',
children: tabPanels.map((panel, index) => ({
li: {
key: index,
className: `tab ${state.activeTab === index ? 'active' : ''}`,
children: [
{
button: {
text: panel.props.label,
onclick: () => setState({ activeTab: index })
}
}
]
}
}))
}
},
// Active tab content
{
div: {
className: 'tab-content',
children: [
tabPanels[state.activeTab]?.children || { div: { text: 'No content' } }
]
}
}
]
}
};
});
const TabPanel = ({ label, children }) => ({
type: 'TabPanel',
props: { label },
children
});
// Usage
const App = () => ({
div: {
children: [
Tabs({
children: [
TabPanel({
label: 'Tab 1',
children: { div: { text: 'Content for tab 1' } }
}),
TabPanel({
label: 'Tab 2',
children: { div: { text: 'Content for tab 2' } }
})
]
})
]
}
});
Slot Pattern
Create components with named slots:
const Card = ({ header, body, footer, ...props }) => ({
div: {
className: `card ${props.className || ''}`,
style: props.style,
children: [
header ? {
div: {
className: 'card-header',
children: Array.isArray(header) ? header : [header]
}
} : null,
body ? {
div: {
className: 'card-body',
children: Array.isArray(body) ? body : [body]
}
} : null,
footer ? {
div: {
className: 'card-footer',
children: Array.isArray(footer) ? footer : [footer]
}
} : null
].filter(Boolean)
}
});
// Usage
const UserCard = ({ user }) => Card({
header: { h3: { text: user.name } },
body: [
{ p: { text: `Email: ${user.email}` } },
{ p: { text: `Role: ${user.role}` } }
],
footer: [
{ button: { text: 'Edit', onclick: () => editUser(user.id) } },
{ button: { text: 'Delete', onclick: () => deleteUser(user.id) } }
]
});
๐ฏ Dynamic Components
Component Registry
Create a system for dynamic component loading:
const componentRegistry = new Map();
const registerComponent = (name, component) => {
componentRegistry.set(name, component);
};
const getComponent = (name) => {
return componentRegistry.get(name);
};
const DynamicComponent = ({ type, props = {} }) => {
const Component = getComponent(type);
if (!Component) {
return {
div: {
className: 'error',
text: `Component "${type}" not found`
}
};
}
return Component(props);
};
// Register components
registerComponent('Button', ({ text, onClick }) => ({
button: { text, onclick: onClick }
}));
registerComponent('Input', ({ value, onChange, placeholder }) => ({
input: {
type: 'text',
value,
oninput: onChange,
placeholder
}
}));
// Usage
const FormBuilder = ({ fields }) => ({
form: {
children: fields.map(field => DynamicComponent({
type: field.type,
props: field.props
}))
}
});
const dynamicForm = FormBuilder({
fields: [
{ type: 'Input', props: { placeholder: 'Name' } },
{ type: 'Input', props: { placeholder: 'Email' } },
{ type: 'Button', props: { text: 'Submit' } }
]
});
Conditional Component Loading
const ConditionalRenderer = ({ condition, components }) => {
if (typeof condition === 'function') {
const result = condition();
return components[result] || components.default || { div: { text: 'No match' } };
}
return components[condition] || components.default || { div: { text: 'No match' } };
};
// Usage
const UserDisplay = ({ user, isAdmin }) => ConditionalRenderer({
condition: () => {
if (!user) return 'guest';
if (isAdmin) return 'admin';
return 'user';
},
components: {
guest: { div: { text: 'Please log in' } },
user: { div: { text: `Welcome, ${user.name}` } },
admin: { div: { text: `Admin: ${user.name}` } },
default: { div: { text: 'Unknown user type' } }
}
});
๐ Async Components
Lazy Loading Components
const LazyComponent = ({ loader, fallback, ...props }) => {
return withState({
Component: null,
loading: false,
error: null
})(({ state, stateUtils }) => {
const { setState } = stateUtils;
if (!state.Component && !state.loading) {
setState({ loading: true });
loader()
.then(module => {
setState({
Component: module.default || module,
loading: false
});
})
.catch(error => {
setState({
error: error.message,
loading: false
});
});
}
if (state.error) {
return {
div: {
className: 'lazy-error',
text: `Failed to load component: ${state.error}`
}
};
}
if (state.loading || !state.Component) {
return fallback || { div: { text: 'Loading component...' } };
}
return state.Component(props);
});
};
// Usage
const App = () => ({
div: {
children: [
LazyComponent({
loader: () => import('./HeavyComponent.js'),
fallback: { div: { text: 'Loading heavy component...' } },
someProp: 'value'
})
]
}
});
Data-Dependent Components
const DataDependentComponent = ({ dataSource, dependencies = [] }) => {
return withState({
data: null,
loading: false,
error: null,
lastDependencies: null
})(({ state, stateUtils }) => {
const { setState } = stateUtils;
const depsChanged = !state.lastDependencies ||
JSON.stringify(dependencies) !== JSON.stringify(state.lastDependencies);
if (depsChanged && !state.loading) {
setState({
loading: true,
error: null,
lastDependencies: dependencies
});
dataSource(dependencies)
.then(data => setState({ data, loading: false }))
.catch(error => setState({ error: error.message, loading: false }));
}
if (state.loading) {
return { div: { text: 'Loading data...' } };
}
if (state.error) {
return { div: { text: `Error: ${state.error}` } };
}
return {
div: {
children: [
{ h3: { text: 'Data-Dependent Component' } },
state.data ? {
pre: { text: JSON.stringify(state.data, null, 2) }
} : { div: { text: 'No data' } }
]
}
};
});
};
๐จ Style and Theme Management
CSS-in-JS Pattern
const createStyles = (theme) => ({
container: {
backgroundColor: theme.colors.background,
color: theme.colors.text,
padding: theme.spacing.medium,
borderRadius: theme.borderRadius,
fontFamily: theme.fonts.body
},
button: {
backgroundColor: theme.colors.primary,
color: theme.colors.white,
border: 'none',
padding: `${theme.spacing.small} ${theme.spacing.medium}`,
borderRadius: theme.borderRadius,
cursor: 'pointer',
fontWeight: 'bold'
},
input: {
border: `1px solid ${theme.colors.border}`,
padding: theme.spacing.small,
borderRadius: theme.borderRadius,
fontSize: theme.fonts.size.medium
}
});
const styleToString = (styleObj) => {
return Object.entries(styleObj)
.map(([key, value]) => `${key.replace(/([A-Z])/g, '-\$1').toLowerCase()}: ${value}`)
.join('; ');
};
const ThemedComponent = withTheme(({ theme, ...props }) => {
const styles = createStyles(theme);
return {
div: {
style: styleToString(styles.container),
children: [
{
input: {
style: styleToString(styles.input),
placeholder: 'Enter text...'
}
},
{
button: {
style: styleToString(styles.button),
text: 'Submit'
}
}
]
}
};
});
Responsive Components
const useMediaQuery = (query) => {
return withState({ matches: false })(({ state, stateUtils }) => {
const { setState } = stateUtils;
if (typeof window !== 'undefined' && !state._initialized) {
const mediaQuery = window.matchMedia(query);
setState({
matches: mediaQuery.matches,
_initialized: true
});
const handler = (e) => setState({ matches: e.matches });
mediaQuery.addEventListener('change', handler);
// Cleanup would need to be handled in a real implementation
}
return state.matches;
});
};
const ResponsiveGrid = ({ items }) => {
const isMobile = useMediaQuery('(max-width: 768px)');
const isTablet = useMediaQuery('(max-width: 1024px)');
const getColumns = () => {
if (isMobile) return 1;
if (isTablet) return 2;
return 3;
};
const columns = getColumns();
return {
div: {
style: `
display: grid;
grid-template-columns: repeat(${columns}, 1fr);
gap: 1rem;
padding: 1rem;
`,
children: items.map((item, index) => ({
div: {
key: index,
style: `
border: 1px solid #ccc;
padding: 1rem;
border-radius: 4px;
`,
children: [
{ h3: { text: item.title } },
{ p: { text: item.description } }
]
}
}))
}
};
};
โก Performance Optimization
Memoization
const memoizeComponent = (Component, keyExtractor = JSON.stringify) => {
const cache = new Map();
return (props) => {
const key = keyExtractor(props);
if (cache.has(key)) {
return cache.get(key);
}
const result = Component(props);
cache.set(key, result);
// Cleanup old entries to prevent memory leaks
if (cache.size > 100) {
const firstKey = cache.keys().next().value;
cache.delete(firstKey);
}
return result;
};
};
// Usage
const ExpensiveComponent = memoizeComponent(({ data }) => {
// Expensive computation
const processedData = data.map(item => ({
...item,
processed: heavyComputation(item)
}));
return {
div: {
children: processedData.map(item => ({
div: { key: item.id, text: item.processed }
}))
}
};
});
Virtual Scrolling
const VirtualList = ({ items, itemHeight = 50, visibleCount = 10 }) => {
return withState({
scrollTop: 0,
containerHeight: visibleCount * itemHeight
})(({ state, stateUtils }) => {
const { setState } = stateUtils;
const totalHeight = items.length * itemHeight;
const startIndex = Math.floor(state.scrollTop / itemHeight);
const endIndex = Math.min(
startIndex + visibleCount + 1,
items.length
);
const visibleItems = items.slice(startIndex, endIndex);
const offsetY = startIndex * itemHeight;
return {
div: {
style: `
height: ${state.containerHeight}px;
overflow-y: auto;
position: relative;
`,
onscroll: (e) => {
setState({ scrollTop: e.target.scrollTop });
},
children: [
// Spacer for total height
{
div: {
style: `height: ${totalHeight}px; position: relative;`,
children: [
// Visible items container
{
div: {
style: `
position: absolute;
top: ${offsetY}px;
left: 0;
right: 0;
`,
children: visibleItems.map((item, index) => ({
div: {
key: startIndex + index,
style: `
height: ${itemHeight}px;
display: flex;
align-items: center;
padding: 0 1rem;
border-bottom: 1px solid #eee;
`,
children: [
{ span: { text: item.name } }
]
}
}))
}
}
]
}
}
]
}
};
});
};
๐งช Testing Advanced Components
Component Testing Utilities
const createTestRenderer = () => {
const renders = [];
const mockRenderer = (component) => {
renders.push(component);
return JSON.stringify(component);
};
return {
render: mockRenderer,
getRenders: () => renders,
getLastRender: () => renders[renders.length - 1],
clearRenders: () => renders.length = 0
};
};
// Test HOCs
test('withLoading HOC shows loading state', () => {
const TestComponent = ({ data }) => ({
div: { text: `Data: ${data}` }
});
const LoadingTestComponent = withLoading(TestComponent);
const renderer = createTestRenderer();
// Should show loading initially
const result = LoadingTestComponent({ data: 'test' });
expect(result).toMatchObject({
div: {
className: 'loading-container'
}
});
});
// Test state changes
test('component state updates correctly', () => {
const stateLogs = [];
const TestComponent = withState({ count: 0 }, {
debug: true,
onStateChange: (oldState, newState) => {
stateLogs.push({ old: oldState, new: newState });
}
})(({ state, stateUtils }) => {
const { setState } = stateUtils;
return {
div: {
children: [
{ span: { text: `Count: ${state.count}` } },
{
button: {
onclick: () => setState({ count: state.count + 1 })
}
}
]
}
};
});
// Test state change logic
expect(stateLogs).toHaveLength(1); // Initial state
});
๐ Best Practices for Advanced Components
1. Component Composition Over Inheritance
// โ
Good - Composition
const EnhancedButton = (props) => BaseButton({
...props,
className: `${props.className} enhanced`,
children: [
{ span: { className: 'icon' } },
...props.children
]
});
// โ Avoid - Complex inheritance
class ComplexButton extends BaseButton {
// Complex inheritance hierarchy
}
2. Clear Component Contracts
const Button = ({
text,
variant = 'primary',
size = 'medium',
disabled = false,
onClick,
...props
}) => {
// Validate props
if (!text && !props.children) {
console.warn('Button requires either text or children');
}
return {
button: {
className: `btn btn--${variant} btn--${size}`,
disabled,
onclick: disabled ? undefined : onClick,
...props,
children: text ? [{ span: { text } }] : props.children
}
};
};
3. Error Boundaries
const withErrorBoundary = (Component, fallback) => {
return (props) => {
try {
return Component(props);
} catch (error) {
console.error('Component error:', error);
return fallback ? fallback(error, props) : {
div: {
className: 'error',
text: 'Something went wrong'
}
};
}
};
};
4. Performance Monitoring
const withPerformanceTracking = (Component, componentName) => {
return (props) => {
const start = Date.now();
const result = Component(props);
const end = Date.now();
if (end - start > 10) {
console.warn(`Component ${componentName} took ${end - start}ms to render`);
}
return result;
};
};
These advanced patterns enable you to build sophisticated, maintainable, and performant applications with Coherent.js. Combine these techniques as needed while keeping components focused and testable.