This project now uses Zustand for centralized state management. Zustand is a lightweight, simple state management library that:
- Requires no providers or context setup
- Works great with TypeScript
- Has minimal boilerplate
- Supports async actions naturally
- Prevents unnecessary re-renders with selective subscriptions
- Reactive UI state: Channels, peers, status, errors
- Serializable data only: No RTCPeerConnection, MediaStream, or RealtimeChannel
- Non-reactive WebRTC objects: RTCPeerConnection, MediaStream, RealtimeChannel
- Centralized refs: Shared across components but not reactive
- Helper functions: Cleanup utilities
- Selective subscriptions: Prevents unnecessary re-renders
- Computed selectors: Derived state like
useActivePeer
Before:
const [streamingPeers, setStreamingPeers] = useState<StreamingPeer[]>([]);
const [activePeerId, setActivePeerId] = useState<string | null>(null);After:
import { useHostState, useHostActions } from "../store/channelStoreHelpers";
const { streamingPeers, activePeerId } = useHostState();
const { setActivePeerId, addStreamingPeer } = useHostActions();Before:
const hostSessionsRef = useRef<Map<string, HostSession>>(new Map());
const hostKeyPairRef = useRef<HostKeyPair | null>(null);After:
import { hostSessionsRef, hostKeyPairRef } from "../store/webrtcRefs";
// Use directly - no need for .current
hostSessionsRef.set(peerId, session);
const keyPair = hostKeyPairRef.current;Before:
const handlePeerOffer = useCallback(async (payload) => {
setStreamingPeers((prev) => [...prev, newPeer]);
}, []);After:
import { useHostActions } from "../store/channelStoreHelpers";
const { addStreamingPeer } = useHostActions();
const handlePeerOffer = useCallback(async (payload) => {
addStreamingPeer(newPeer);
}, [addStreamingPeer]);- No dependency issues: Zustand actions are stable references
- Centralized state: Easy to debug and inspect
- Selective re-renders: Components only re-render when their selected state changes
- Type-safe: Full TypeScript support
- Simple API: No providers, no context, just hooks
See src/screens/ChannelListScreen.tsx for a complete example of a migrated component.
- Migrate
ChannelListScreen.tsx(simplest, good starting point) - Migrate
ChannelPeerScreen.tsx(peer state) - Migrate
ChannelHostScreen.tsx(most complex, host state) - Remove old useState/useRef patterns
- Test thoroughly