React Context vs Redux: State Management for Web3 DApps
React Context vs Redux: State Management for Web3 DApps
After building ClawDUX with React Context, here's our honest assessment of when it works and when you need more.
TL;DR Decision Framework
| Scenario | Use Context | Use Redux/Zustand |
|---|---|---|
| Auth/wallet state | Yes | Overkill |
| 1-2 global values | Yes | Overkill |
| Complex transaction queue | No | Yes |
| >5 consumers of same state | Maybe | Probably |
| Time-travel debugging needed | No | Yes |
How We Use Context on ClawDUX
// WalletContext.tsx - Our entire global state
interface WalletState {
address: string | null;
user: User | null;
usdcBalance: string;
isConnected: boolean;
isLoading: boolean;
}
const WalletContext = createContext<WalletState & WalletActions>(
{} as any
);
export function WalletProvider({ children }: Props) {
const [address, setAddress] = useState<string | null>(null);
const [user, setUser] = useState<User | null>(null);
const [usdcBalance, setUsdcBalance] = useState('0');
// Auth methods
const loginWithEmail = async (email: string, password: string) => {
const { token, user } = await api.login(email, password);
localStorage.setItem('clawdux_token', token);
setUser(user);
setAddress(user.walletAddress);
};
const connectMetaMask = async () => {
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
setAddress(await signer.getAddress());
};
// Balance polling
useEffect(() => {
if (!address) return;
const interval = setInterval(refreshBalance, 15000);
return () => clearInterval(interval);
}, [address]);
return (
<WalletContext.Provider value={{
address, user, usdcBalance, isConnected: !!address,
loginWithEmail, connectMetaMask, disconnect,
}}>
{children}
</WalletContext.Provider>
);
}
Why Context Works Here
- Single source of truth: Only one wallet connection at a time
- Infrequent updates: Balance changes every 15s, not every frame
- Simple shape: ~5 state values, not a complex nested object
- Few consumers: Navbar, Dashboard, Purchase Modal — maybe 5 components
When We'd Switch to Redux
If we added:
- Real-time order book with 100+ updates/second
- Multi-tab synchronization
- Complex undo/redo for order management
- Server state caching (though React Query handles this better)
The Practical Hybrid
// Context for auth/wallet (simple, global)
<WalletProvider>
{/* React Query for server state (cached, auto-refetching) */}
<QueryClientProvider client={queryClient}>
{/* Local state for everything else */}
<App />
</QueryClientProvider>
</WalletProvider>
For ClawDUX's scale — a marketplace with hundreds of listings, real-time notifications, and wallet integration — React Context + component-level state has been sufficient. We haven't needed Redux, and that's a feature, not a limitation.
The core logic discussed in this article has been integrated into the ClawDUX API. Access ClawDUX-core for full permissions, or browse the marketplace to discover verified trading strategies.