A guide to writing clean, efficient, and maintainable code with Reflex.
Only make values reactive when they need to be. Not everything needs to be reactive.
✅ Good:
// Only the active filter is reactive
const activeFilter = reflex({ initialValue: 'all' });
const filters = ['all', 'active', 'completed']; // Static value
❌ Bad:
// Don't make static values reactive
const filters = reflex({
initialValue: ['all', 'active', 'completed']
});
Don't manually sync dependent values. Use computed values instead.
✅ Good:
const firstName = reflex({ initialValue: 'John' });
const lastName = reflex({ initialValue: 'Doe' });
const fullName = computed(
[firstName, lastName],
([first, last]) => `${first} ${last}`
);
❌ Bad:
const firstName = reflex({ initialValue: 'John' });
const lastName = reflex({ initialValue: 'Doe' });
const fullName = reflex({ initialValue: 'John Doe' });
// Manual syncing is error-prone
firstName.subscribe(first => {
fullName.setValue(`${first} ${lastName.getValue()}`);
});
lastName.subscribe(last => {
fullName.setValue(`${firstName.getValue()} ${last}`);
});
Prevent memory leaks by cleaning up subscriptions when they're no longer needed.
✅ Good:
class Component {
private subscriptions: Array<() => void> = [];
init() {
this.subscriptions.push(
value.subscribe(this.handleValue)
);
}
destroy() {
this.subscriptions.forEach(unsubscribe => unsubscribe());
this.subscriptions = [];
}
}
❌ Bad:
class Component {
init() {
// Subscription is never cleaned up
value.subscribe(this.handleValue);
}
}
Take advantage of Reflex's cleanup methods for automatic memory management.
✅ Good:
const value = reflex({ initialValue: 0 });
// Later when done
value.cleanup(); // Removes all subscriptions
Prevent unnecessary updates with custom equality checks when needed.
✅ Good:
const position = reflex({
initialValue: { x: 0, y: 0 },
equals: (prev, next) =>
Math.abs(prev.x - next.x) < 0.001 &&
Math.abs(prev.y - next.y) < 0.001
});
Use batching for multiple related updates.
✅ Good:
Reflex.batch(() => {
position.setValue({ x: 10, y: 20 });
scale.setValue(2);
rotation.setValue(45);
});
❌ Bad:
// Each setValue triggers updates separately
position.setValue({ x: 10, y: 20 });
scale.setValue(2);
rotation.setValue(45);
Handle errors gracefully with error handlers.
✅ Good:
const value = reflex({
initialValue: 0,
onError: (error) => {
console.error('Value error:', error);
return 0; // Fallback value
}
});
Use middleware for validation.
✅ Good:
const age = reflex({
initialValue: 0,
middleware: [
value => {
if (value < 0) throw new Error('Age cannot be negative');
if (value > 150) throw new Error('Invalid age');
return value;
}
]
});
Keep related state together and organized.
✅ Good:
class UserState {
readonly profile = deepReflex({
initialValue: {
name: '',
email: '',
preferences: {}
}
});
readonly isLoggedIn = computed(
[this.profile],
([profile]) => Boolean(profile.email)
);
}
Take advantage of TypeScript for better type safety.
✅ Good:
interface User {
id: string;
name: string;
email: string;
}
const user = reflex<User>({
initialValue: {
id: '',
name: '',
email: ''
}
});
Enable debug mode during development.
✅ Good:
const debugValue = reflex({
initialValue: 0,
debug: process.env.NODE_ENV === 'development'
});
Use middleware for debugging when needed.
✅ Good:
const value = reflex({
initialValue: 0,
middleware: [
value => {
console.log('Value changing to:', value);
return value;
}
]
});
Create clean integrations with your framework.
✅ Good:
// React Hook
function useReflex<T>(value: Reflex<T>): T {
const [state, setState] = useState(value.getValue());
useEffect(() => {
return value.subscribe(setState);
}, [value]);
return state;
}
Separate framework-specific code from your state logic.
✅ Good:
// State logic
class TodoState {
items = reflex({ initialValue: [] });
addItem(item) { /* ... */ }
removeItem(id) { /* ... */ }
}
// React component
function TodoList() {
const todos = useReflex(todoState.items);
return (
<ul>
{todos.map(todo => (
<TodoItem key={todo.id} todo={todo} />
))}
</ul>
);
}
Write tests for your state logic.
✅ Good:
describe('TodoState', () => {
it('should add items', () => {
const state = new TodoState();
state.addItem({ id: 1, text: 'Test' });
expect(state.items.getValue()).toHaveLength(1);
});
});
- Review the API Reference for detailed method documentation
- See Advanced Usage Guide for complex patterns
- Check out Performance Tips for more optimization strategies