Appearance
Best Practices
Learn the best practices for using Nexus State effectively in your applications.
General Guidelines
1. Use Descriptive Atom Names
Always give your atoms descriptive names for better debugging experience:
typescript
// Bad
const a = atom(0);
// Good
const countAtom = atom(0, 'counter');
const userAtom = atom({ name: '' }, 'user-profile');2. Keep Atoms Small and Focused
Break down complex state into multiple small atoms rather than using large objects:
typescript
// Bad
const complexState = atom({
user: { name: '', email: '' },
settings: { theme: 'light', language: 'en' },
preferences: { notifications: true }
});
// Good
const userAtom = atom({ name: '', email: '' }, 'user');
const settingsAtom = atom({ theme: 'light', language: 'en' }, 'settings');
const preferencesAtom = atom({ notifications: true }, 'preferences');3. Use Computed Atoms for Derived State
Instead of recalculating derived values, use computed atoms:
typescript
// Bad
const total = computed(() => items.reduce((sum, item) => sum + item.price, 0));
// Good
const totalAtom = atom((get) => {
const items = get(itemsAtom);
return items.reduce((sum, item) => sum + item.price, 0);
}, 'total');Framework-Specific Best Practices
React
1. Use Hooks Properly
typescript
// Bad - Unnecessary re-renders
function Counter() {
const count = useAtom(countAtom);
return <div>{count}</div>;
}
// Good - Extract only needed values
function Counter() {
const [count, setCount] = useAtom(countAtom);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}2. Use Selector Pattern for Performance
typescript
// Bad - Component re-renders on any state change
function CounterDisplay() {
const state = useAtom(stateAtom);
return <div>{state.count}</div>;
}
// Good - Only re-renders when count changes
function CounterDisplay() {
const count = useAtomState(stateAtom, (state) => state.count);
return <div>{count}</div>;
}Vue
1. Use Composition API
typescript
// Bad - Options API
export default {
setup() {
const count = useAtom(countAtom);
return { count };
}
};
// Good - Composition API with reactive
import { computed } from 'vue';
export default {
setup() {
const count = useAtom(countAtom);
const doubled = computed(() => count.value * 2);
return { count, doubled };
}
};Svelte
1. Use Svelte's Reactive Declarations
typescript
// Good - Leverage Svelte's reactivity
<script>
import { useAtom } from '@nexus-state/svelte';
import { countAtom } from './store';
let count = useAtom(countAtom);
$: doubled = count * 2;
</script>
<p>Count: {count}</p>
<p>Doubled: {doubled}</p>Time Travel Best Practices
1. Use Descriptive Snapshot Names
typescript
// Good
store.captureSnapshot('Form Submission');
store.captureSnapshot('User Login');
store.captureSnapshot('Data Fetched');2. Limit History Size
typescript
const store = createEnhancedStore([], {
enableTimeTravel: true,
maxHistory: 50 // Adjust based on your needs
});3. Use Manual Snapshots for Important Actions
typescript
// Bad - Every action creates a snapshot
const store = createEnhancedStore([], { autoCapture: true });
// Good - Control snapshots for meaningful history points
const store = createEnhancedStore([], {
enableTimeTravel: true,
autoCapture: false
});
store.set(countAtom, 5);
store.captureSnapshot('User Adjusted Count');Performance Optimization
1. Batch Updates
typescript
// Bad - Multiple updates cause multiple re-renders
store.set(countAtom, 1);
store.set(nameAtom, 'John');
store.set(emailAtom, 'john@example.com');
// Good - Batch updates
store.batch(() => {
store.set(countAtom, 1);
store.set(nameAtom, 'John');
store.set(emailAtom, 'john@example.com');
});2. Use Selectors in Framework Integrations
typescript
// React example
const count = useAtomState(countAtom, (state) => state.count);3. Avoid Unnecessary Computations
typescript
// Bad - Expensive computation in computed atom
const expensiveAtom = atom((get) => {
const data = get(dataAtom);
return expensiveFunction(data); // Runs on every access
});
// Good - Use derived state with caching
const derivedAtom = atom((get) => {
const data = get(dataAtom);
return processDerivedData(data); // Cached result
});Testing Best Practices
1. Test Atoms in Isolation
typescript
// Example.test.ts
import { atom } from '@nexus-state/core';
import { createEnhancedStore } from '@nexus-state/core';
describe('Counter Atom', () => {
it('should increment correctly', () => {
const countAtom = atom(0, 'count');
const store = createEnhancedStore();
expect(store.get(countAtom)).toBe(0);
store.set(countAtom, 1);
expect(store.get(countAtom)).toBe(1);
});
});2. Test Time Travel Functionality
typescript
it('should support undo/redo', () => {
const countAtom = atom(0, 'count');
const store = createEnhancedStore([], { enableTimeTravel: true });
store.set(countAtom, 1);
store.set(countAtom, 2);
expect(store.get(countAtom)).toBe(2);
store.undo();
expect(store.get(countAtom)).toBe(1);
store.redo();
expect(store.get(countAtom)).toBe(2);
});Common Pitfalls
1. Overusing Global State
Don't put everything in global state. Consider local state for UI-only data.
2. Large Atoms
Avoid large, complex atoms. Break them down into smaller, focused atoms.
3. Ignoring Performance
Use selectors, batching, and computed atoms wisely to maintain performance.
4. Not Using Names
Always name your atoms for better debugging experience.