On RxJS reactive programming: many developers only operate at the API-call level. This post tries to look at the real problems and solutions from a production perspective.
Basic Principles
Building on this, we can take it further:
import { create } from 'zustand'
import { persist, devtools } from 'zustand/middleware'
const useStore = create(
devtools(persist(
(set, get) => ({
user: null,
theme: 'light',
notifications: [],
setUser: (user) => set({ user }),
toggleTheme: () => set(s => ({
theme: s.theme === 'light' ? 'dark' : 'light'
})),
unreadCount: () => get().notifications.filter(n => !n.read).length
}),
{ name: 'app-store' }
))
)
This pattern is very useful in large projects and noticeably cuts maintenance cost.
Advanced Features
In real projects the usage gets more involved:
import { create } from 'zustand'
import { persist, devtools } from 'zustand/middleware'
const useStore = create(
devtools(persist(
(set, get) => ({
user: null,
theme: 'light',
notifications: [],
setUser: (user) => set({ user }),
toggleTheme: () => set(s => ({
theme: s.theme === 'light' ? 'dark' : 'light'
})),
unreadCount: () => get().notifications.filter(n => !n.read).length
}),
{ name: 'app-store' }
))
)
This way, both the testability and extensibility of the code improve.
Project Practice
Here is a complete example:
import { create } from 'zustand'
import { persist, devtools } from 'zustand/middleware'
const useStore = create(
devtools(persist(
(set, get) => ({
user: null,
theme: 'light',
notifications: [],
setUser: (user) => set({ user }),
toggleTheme: () => set(s => ({
theme: s.theme === 'light' ? 'dark' : 'light'
})),
unreadCount: () => get().notifications.filter(n => !n.read).length
}),
{ name: 'app-store' }
))
)
Mind the edge-case handling — that's critical in production.
Best Practices
The key is understanding the core logic:
import { create } from 'zustand'
import { persist, devtools } from 'zustand/middleware'
const useStore = create(
devtools(persist(
(set, get) => ({
user: null,
theme: 'light',
notifications: [],
setUser: (user) => set({ user }),
toggleTheme: () => set(s => ({
theme: s.theme === 'light' ? 'dark' : 'light'
})),
unreadCount: () => get().notifications.filter(n => !n.read).length
}),
{ name: 'app-store' }
))
)
Performance optimization has to fit the context; not every case needs over-optimization.
Common Pitfalls
Here's how we can improve it:
import { create } from 'zustand'
import { persist, devtools } from 'zustand/middleware'
const useStore = create(
devtools(persist(
(set, get) => ({
user: null,
theme: 'light',
notifications: [],
setUser: (user) => set({ user }),
toggleTheme: () => set(s => ({
theme: s.theme === 'light' ? 'dark' : 'light'
})),
unreadCount: () => get().notifications.filter(n => !n.read).length
}),
{ name: 'app-store' }
))
)
This approach has been running stably in production for over half a year and is proven in practice.
Summary
- In a team, conventions and docs matter more than the tech itself
- Keep an eye on the community; technical approaches need continuous iteration
- Don't adopt new tech just for its own sake
- Code samples are for reference only — adapt them to your use case
