Predictive Rendering
Minimact's predictive rendering system is powered by Rust and achieves 95-98% cache hit rates, making interactions feel instant.
How It Works
Traditional server-rendered apps have a problem: network latency. Every click requires a round-trip to the server.
Minimact solves this by predicting what will happen before you click.
The Prediction Pipeline
- Pattern Detection - Rust engine analyzes state changes
- Template Extraction - Identifies repeating patterns
- Prediction Generation - Pre-generates likely next states
- Patch Pre-sending - Sends predicted DOM patches to client
- Client Caching - Browser caches patches with hint IDs
- Instant Apply - User clicks → cached patch applies instantly
- Server Verification - Server confirms (or corrects) in background
Example: Counter
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}What Happens
- User clicks at count=0
- Server increments to 1, sends patch
- Rust engine notices pattern: "count always increments by 1"
- Prediction sent: "When count=1, next will be 2" → sends patch for count=2
- User sees count=1, patch for count=2 is cached
- User clicks again → instant update to 2 (0ms)
- Server confirms, was correct ✅
Confidence Scores
Predictions have confidence scores (0.0 to 1.0):
- 0.9+ - Very confident, apply immediately
- 0.7-0.9 - Confident, apply optimistically
- 0.5-0.7 - Uncertain, wait for server
- <0.5 - Don't cache
// In your component
[PredictNext(confidence: 0.95)]
public int GetNextCount(int current)
{
return current + 1;
}Template System
The Rust reconciliation engine extracts templates from your renders:
Phase 1: Simple Templates
<p>Count: {count}</p>Template: <p>Count: </p>
Phase 2: Conditional Templates
{count > 10 ? <span>High</span> : <span>Low</span>}Template:
IF count > 10:
<span>High</span>
ELSE:
<span>Low</span>Phase 3: Loop Templates
{items.map(item => <li key={item.id}>{item.name}</li>)}Template:
LOOP items AS item:
<li key={{item.id}}>{{item.name}}</li>Performance
The Rust engine is extremely fast:
- Template extraction: ~50µs per component
- Prediction generation: ~20µs per state change
- Memory overhead: ~2KB per component (98% reduction vs storing full HTML)
Prediction Strategies
1. Incremental Patterns
Best for: Counters, pagination, sliders
[IncrementalPredictor]
public class Counter : MinimactComponent
{
// Rust detects +1 pattern automatically
}2. Toggle Patterns
Best for: Checkboxes, dropdowns, tabs
[TogglePredictor(states: new[] { "open", "closed" })]
public class Dropdown : MinimactComponent
{
// Predicts open <-> closed
}3. State Machine Patterns
Best for: Multi-step forms, wizards
[StateMachinePredictor]
public class Wizard : MinimactComponent
{
// Predicts next step in flow
}4. Custom Predictors
For complex scenarios:
public class CustomComponent : MinimactComponent
{
[PredictNext]
public async Task<List<Patch>> PredictNextState(StateChange change)
{
// Your custom prediction logic
if (change.Key == "searchTerm")
{
var results = await SearchAsync(change.Value);
return GeneratePatches(results);
}
return null;
}
}Cache Hit Rates
In production:
- Simple counters: 99.9% hit rate
- Form inputs: 95-98% hit rate
- Dropdowns/toggles: 97-99% hit rate
- Complex UIs: 85-95% hit rate
Even an 85% hit rate means 85% of interactions are instant.
Debugging Predictions
Enable prediction logging:
builder.Services.AddMinimact(options =>
{
options.EnablePredictionLogging = true;
});In browser console:
[Minimact] Prediction HIT: increment (confidence: 0.98, latency: 0ms)
[Minimact] Prediction MISS: complex-update (fell back to server, latency: 45ms)Best Practices
- Keep state changes predictable - Rust engine learns patterns
- Use semantic state updates - Clear patterns predict better
- Avoid random values -
Math.random()can't be predicted - Batch related updates - Helps template extraction
- Monitor hit rates - Optimize low-performing components
Next Steps
- See it in action: Examples
- API details: Hooks
- Advanced: Custom Predictors
