diff options
| author | Adam Mathes <adam@adammathes.com> | 2026-02-15 15:57:54 -0800 |
|---|---|---|
| committer | Adam Mathes <adam@adammathes.com> | 2026-02-15 15:57:54 -0800 |
| commit | 4cd15bb8a04bf8df3fb292796a8f32d7533cacdc (patch) | |
| tree | 3319c61a2fd41cacb8f94a5bb39c40baa9c3d624 /performance_analysis.md | |
| parent | f056c01f56fc387a5a6cb4c55bc0edbdff086a5d (diff) | |
| download | neko-4cd15bb8a04bf8df3fb292796a8f32d7533cacdc.tar.gz neko-4cd15bb8a04bf8df3fb292796a8f32d7533cacdc.tar.bz2 neko-4cd15bb8a04bf8df3fb292796a8f32d7533cacdc.zip | |
Optimize frontend with memoized FeedItem and efficient IntersectionObserver
Diffstat (limited to 'performance_analysis.md')
| -rw-r--r-- | performance_analysis.md | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/performance_analysis.md b/performance_analysis.md new file mode 100644 index 0000000..2071114 --- /dev/null +++ b/performance_analysis.md @@ -0,0 +1,35 @@ +# Performance Analysis & Recommendations + +## Executive Summary +You are correct that the React implementation introduces inherent latency compared to the vanilla JS/Backbone version, particularly during initial load and interactions. While backend measurements show fast response times (~5ms) for the current dataset (where `full_content` is mostly empty), the React frontend's rendering strategy and bundle overhead are the primary contributors to the perceived slowness. + +## Key Findings + +### 1. React Rendering Overhead vs. Vanilla JS +- **Initial Load**: The React application requires downloading a larger bundle (~241KB vs ~150KB for legacy) and then executing hydration before fetching data. This adds an initial delay (Time to Interactive) not present in the lightweight vanilla version. +- **Excessive Re-rendering**: The current `FeedItems` component triggers a re-render of the **entire list** (and all children `FeedItem` components) whenever a single item is selected or modified. React's reconciliation process diffs every item, which is computationally expensive compared to Backbone's direct DOM manipulation of a single element. +- **DOM Node Count**: Even with small content, rendering 15+ complex article cards with `dangerouslySetInnerHTML` involves significant DOM operations. React's synthetic event system and component overhead add micro-latency per item. + +### 2. Implementation Inefficiencies +- **Observer Churn**: The `IntersectionObserver` in `FeedItems.tsx` disconnects and reconnects for *every item* whenever the list updates or state changes. This is an O(N) operation that degrades performance as the list grows. +- **Lack of Memoization**: `FeedItem` components are not memoized (`React.memo`), causing them to re-render unnecessarily on parent state changes (like selecting an item with `j`/`k`). + +### 3. Backend Data Strategy (Minor Current Impact, Major Risk) +- Although `full_content` is currently empty for most items, the backend still retrieves and serializes this field for every item in the list. This is "fast enough" now (5ms) but remains a structural inefficiency that will cause severe slowdowns if/when content is scraped. + +## Recommendations + +### 1. Optimize React Rendering (High Impact) +The most effective way to restore "snappiness" is to reduce React's work: +- **Memoize `FeedItem`**: Wrap the component in `React.memo` so it only re-renders when its specific props change. This prevents the entire list from flashing when you select one item. +- **Virtualize Long Lists**: Implement `react-window` or `virtuoso` for both the sidebar (`FeedList`) and main view (`FeedItems`). This ensures only visible items are in the DOM, keeping the browser responsive regardless of list size. +- **Stable References**: Use `useCallback` for event handlers passed to children to prevent breaking memoization. + +### 2. Fix Observer & Effect Logic (Medium Impact) +- Refactor the `IntersectionObserver` in `FeedItems.tsx` to maintain a stable observer instance using `useRef` and only observe/unobserve specific elements as needed, rather than resetting the whole list. + +### 3. Backend Optimization (Defensive) +- Even if not the current bottleneck, modifying `item.Filter` to exclude `full_content` on list views is a simple change that prevents future performance regressions. + +## Conclusion +The "sluggishness" is primarily due to React's re-rendering of the entire list on interactions and the initial hydration cost. Implementing **Memoization** and **Virtualization** will bring the responsiveness much closer to the vanilla JS experience. |
