Last updated: Sep 1, 2025, 01:10 PM UTC

Comprehensive Fix Plan for Sasha Studio Re-Render Issues

Version: 1.0.0
Status: ACTIVE
Date: 2025-01-29
Priority: CRITICAL

Executive Summary

Sasha Studio currently experiences 10-20 component re-renders per user action due to replacing entire message arrays when only one message is added. This plan consolidates all technical documents into a single, actionable implementation guide focused on message streaming as the primary solution.

Related Documents

The Core Problem

// CURRENT: Every message update replaces entire array
messages: [...100 existing messages, 1 new message] // New array = React re-renders everything

// TARGET: Stream individual messages
message: { id: 'msg-101', content: '...', isStreaming: true } // Append only = minimal re-render

Priority Implementation Order

πŸ”΄ CRITICAL PATH (Must Do First)

Week 1: Foundation (3 days)

  1. Fix useEffect dependencies (App.jsx lines 128-209)

    • Split 80-line mega useEffect
    • Use primitives: [selectedProject?.id] not [projects]
    • Impact: 30% reduction in re-renders
  2. Remove unused flags (projectReducer.js)

    • Delete isProcessingWebSocket, isNavigating
    • Impact: Cleaner state, fewer updates
  3. Clean storage

    • Remove sasha_chat_messages_* from localStorage
    • Impact: Eliminates duplicate state sources

Week 2: Message Streaming (5 days) MOST CRITICAL

This phase alone solves 70% of performance issues.

  1. Create JSONL incremental reader (server/services/message-stream.js)
class MessageStreamReader {
  async readNewMessages(filePath, fromPosition) {
    const stream = fs.createReadStream(filePath, { start: fromPosition });
    // Read only NEW lines, not entire file
    return newMessages;
  }
}
  1. Implement streaming WebSocket (server/index.js)
// STOP sending this:
io.emit('projects_updated', { projects: [...] }); // 100KB

// START sending this:
io.emit('message_streamed', { 
  sessionId: 'xxx',
  message: { id: 'msg-123', content: '...' } // 500 bytes
});
  1. Update reducer for streaming (projectReducer.js)
case 'APPEND_MESSAGE':
  // Append single message without replacing array
  return {
    ...state,
    messageStreams: {
      [sessionId]: {
        messages: [...existing, newMessage], // Append only
        isStreaming: true
      }
    }
  };

Week 3: Smart File Watcher (3 days)

  1. Route by file type (server/services/smart-watcher.js)

    • Docs β†’ Toast only (no re-render)
    • Messages β†’ Stream update (1-2 re-renders)
    • Files β†’ Tree update only
  2. Type-specific debouncing

    • Messages: 50ms (real-time feel)
    • Documentation: 1000ms (batch changes)
    • Files: 500ms (balanced)

Week 4: Testing & Rollout (2 days)

  1. Performance validation

    • Measure with React DevTools Profiler
    • Target: 1-2 re-renders per message
    • WebSocket payload <500 bytes
  2. Feature flag rollout

    • 10% β†’ 50% β†’ 100% gradual deployment

🟑 IMPORTANT (But Not Critical Path)

  • URL routing (/project/{name}/chat/{id})
  • React.memo optimization
  • Virtual scrolling for 1000+ messages

🟒 NICE TO HAVE (Do Later)

  • Documentation HTML generation optimization
  • Advanced caching strategies
  • IndexedDB for offline support

File Modification Priority

Must Change First (High Impact)

  1. src/App.jsx - Split useEffect (lines 128-209)
  2. src/reducers/projectReducer.js - Add streaming actions
  3. server/index.js - Implement message streaming

Must Create New

  1. server/services/message-stream.js - JSONL reader
  2. server/services/smart-watcher.js - Intelligent routing

Can Update Later

  • src/components/ChatInterface.jsx - Optimize rendering
  • src/hooks/useProjectWebSocketV2.js - Handle streaming

Success Metrics

Performance Targets (MUST ACHIEVE)

Metric Current Week 2 Target Final Target
Re-renders per message 10-20 3-5 1-2
WebSocket payload ~100KB <5KB <500 bytes
Message latency 800ms 200ms <100ms
File fetches 10-40 5 1

How to Measure

  1. Open React DevTools Profiler
  2. Start recording
  3. Send a message to Claude
  4. Stop recording
  5. Count component renders (target: 1-2)

Implementation Checklist

Week 1: Foundation

  • Split App.jsx mega useEffect
  • Fix all useEffect dependencies
  • Remove unused reducer flags
  • Clean localStorage/sessionStorage
  • Add performance logging

Week 2: Message Streaming (CRITICAL) πŸ”΄

  • Create MessageStreamReader class
  • Track JSONL file positions
  • Send individual messages via WebSocket
  • Implement APPEND_MESSAGE action
  • Test with real Claude responses
  • Verify <500 byte payloads
  • Confirm 1-2 re-renders

Week 3: Smart Watcher

  • Create smart-watcher.js
  • Route by file type
  • Implement type-specific debouncing
  • Documentation β†’ toast only
  • Files β†’ tree update only

Week 4: Validation

  • Run performance tests
  • Deploy with feature flag
  • Monitor metrics
  • Gradual rollout

Common Pitfalls to Avoid

DON'T

  • Send entire message arrays
  • Use objects as useEffect dependencies
  • Replace unchanged state references
  • Debounce messages longer than 50ms
  • Skip performance measurement

DO

  • Stream individual messages
  • Use primitive dependencies
  • Preserve object references
  • Keep message debounce at 50ms
  • Measure before/after each change

Quick Start Commands

# 1. Check current performance
npm run dev
# Open React DevTools, measure re-renders

# 2. Implement message streaming
# Edit server/index.js and projectReducer.js

# 3. Test improvements
# Send messages, measure again

# 4. Deploy with flag
ENABLE_MESSAGE_STREAMING=true npm run dev

Risk Mitigation

  1. Feature Flags: All changes behind ENABLE_MESSAGE_STREAMING flag
  2. Backward Compatibility: Support both old and new message formats
  3. Rollback Plan: Can disable streaming instantly
  4. Monitoring: Log performance metrics before/after

Expected Timeline

  • Day 1-3: Foundation fixes (30% improvement)
  • Day 4-8: Message streaming (70% improvement) πŸ”΄
  • Day 9-11: Smart watcher (10% improvement)
  • Day 12-15: Testing and rollout

Total time: 15 working days (3 weeks)
Critical path: Days 4-8 (message streaming)

Conclusion

The key insight is that message streaming alone solves 70% of the problem. By sending individual messages instead of entire arrays, we eliminate the root cause of excessive re-renders. Everything else is optimization on top of this core fix.

Start with Week 2 (message streaming) if you only have time for one change.