Skip to content

Commit b77ecec

Browse files
committed
feat: add documentation for Scoped Stores in Blazor Server with Redux DevTools support
1 parent 09d8505 commit b77ecec

1 file changed

Lines changed: 123 additions & 0 deletions

File tree

docs-site/render-modes.html

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,129 @@ <h3>Option 2: Switch to Auto mode</h3>
426426
</div>
427427
</section>
428428

429+
<!-- Scoped Stores for Blazor Server -->
430+
<section class="section">
431+
<h2 id="scoped-stores">Scoped Stores for Blazor Server (Now with Redux DevTools! 🎉)</h2>
432+
433+
<div class="alert alert-success">
434+
<div class="alert-title">Major Breakthrough!</div>
435+
<p>Scoped stores in Blazor Server <strong>now support Redux DevTools</strong>! This was previously thought impossible, but we've made it work.</p>
436+
</div>
437+
438+
<h3>The Problem</h3>
439+
<p>In Blazor Server, singleton stores are shared across all SignalR circuits (all connected users). This means every client sees the same state, which is not ideal for user-specific data.</p>
440+
441+
<h3>The Solution</h3>
442+
<p>Use <strong>scoped stores</strong> for per-circuit (per-user) isolation. Each user gets their own instance of the store.</p>
443+
444+
<h3>When to Use Scoped Stores</h3>
445+
<table class="table">
446+
<thead>
447+
<tr>
448+
<th>Scenario</th>
449+
<th>Store Type</th>
450+
</tr>
451+
</thead>
452+
<tbody>
453+
<tr>
454+
<td><strong>User-specific data</strong> (cart, preferences, session)</td>
455+
<td>✅ Scoped</td>
456+
</tr>
457+
<tr>
458+
<td><strong>Shared app data</strong> (product catalog, config)</td>
459+
<td>✅ Singleton</td>
460+
</tr>
461+
<tr>
462+
<td><strong>WebAssembly apps</strong></td>
463+
<td>✅ Singleton (no sharing issue)</td>
464+
</tr>
465+
</tbody>
466+
</table>
467+
468+
<h3>Scoped Store Registration</h3>
469+
<div class="code-block">
470+
<div class="code-block-title">Program.cs - Blazor Server with per-user isolation AND Redux DevTools!</div>
471+
<pre><code class="language-csharp">builder.Services.AddStoreUtilities();
472+
473+
// Scoped store with DevTools - each user gets their own instance
474+
builder.Services.AddScopedStore(
475+
new UserSessionState(),
476+
(store, sp) => store
477+
.WithDevTools(sp, "User Session") // ✅ Redux DevTools work!
478+
.WithLogging());
479+
480+
// Or with utilities (async helpers) + full features
481+
builder.Services.AddScopedStoreWithUtilities(
482+
new ShoppingCartState(),
483+
(store, sp) => store
484+
.WithDefaults(sp, "Shopping Cart") // DevTools + Logging
485+
.WithMiddleware(customMiddleware));</code></pre>
486+
</div>
487+
488+
<div class="alert alert-info">
489+
<div class="alert-title">Key Breakthrough</div>
490+
<p>Scoped stores now accept <code>IServiceProvider</code> in the configure callback, which enables:</p>
491+
<ul style="margin: 0.5rem 0 0 1.5rem;">
492+
<li><strong>Redux DevTools</strong> (IJSRuntime resolved per-circuit!)</li>
493+
<li>✅ Access to scoped services (middleware, validators)</li>
494+
<li>✅ Full feature parity with WebAssembly mode</li>
495+
</ul>
496+
</div>
497+
498+
<h3>Why DevTools Work with Scoped Stores</h3>
499+
<p>The key difference:</p>
500+
<ul>
501+
<li><strong>Singleton stores:</strong> Created at app startup before any circuits exist → No IJSRuntime available</li>
502+
<li><strong>Scoped stores:</strong> Created when SignalR circuits are established → IJSRuntime is available!</li>
503+
</ul>
504+
505+
<div class="code-block">
506+
<div class="code-block-title">Complete Example with All Features</div>
507+
<pre><code class="language-csharp">// ✅ DevTools WORK with scoped stores!
508+
builder.Services.AddScopedStore(
509+
new UserSessionState(),
510+
(store, sp) => store
511+
.WithDevTools(sp, "User Session") // ✅ Works perfectly!
512+
.WithLogging());
513+
514+
// ✅ Complete example with all features
515+
builder.Services.AddScopedStore(
516+
new ShoppingCartState(),
517+
(store, sp) => store
518+
.WithDefaults(sp, "Shopping Cart") // Includes DevTools + Logging
519+
.WithMiddleware(customMiddleware));</code></pre>
520+
</div>
521+
522+
<h3>Accessing Scoped Services</h3>
523+
<p>The new signature enables dependency injection:</p>
524+
<div class="code-block">
525+
<pre><code class="language-csharp">// Register scoped validator
526+
builder.Services.AddScoped&lt;IStateValidator&lt;CartState&gt;, CartValidator&gt;();
527+
528+
// Access it in configure callback
529+
builder.Services.AddScopedStore(
530+
new CartState(),
531+
(store, sp) =>
532+
{
533+
var validator = sp.GetRequiredService&lt;IStateValidator&lt;CartState&gt;&gt;();
534+
return store.WithMiddleware(new ValidationMiddleware&lt;CartState&gt;(validator));
535+
});</code></pre>
536+
</div>
537+
538+
<div class="alert alert-warning">
539+
<div class="alert-title">Limitations</div>
540+
<ul style="margin: 0.5rem 0 0 1.5rem;">
541+
<li>⚠️ LocalStorage persistence has limitations (sessions don't persist across reconnects)</li>
542+
<li>⚠️ Singleton stores still can't use DevTools (created before IJSRuntime exists)</li>
543+
</ul>
544+
</div>
545+
546+
<div class="alert alert-success">
547+
<div class="alert-title">Working Demo</div>
548+
<p>See the <a href="https://github.com/mashrulhaque/EasyAppDev.Blazor.Store/tree/main/samples/EasyAppDev.Blazor.Store.ServerSample" target="_blank">Blazor Server Sample</a> for a working demonstration of scoped stores with Redux DevTools!</p>
549+
</div>
550+
</section>
551+
429552
<!-- Troubleshooting -->
430553
<section class="section">
431554
<h2>Troubleshooting by Render Mode</h2>

0 commit comments

Comments
 (0)