Repository navigation
fix(filter): create new VersionFilter instead of spreading - #226
Merged
stevekaplan123 merged 2 commits intoSep 23, 2026
Merged
Conversation
stevekaplan123
marked this pull request as ready for review
September 15, 2026 10:52
📊 Code Quality Score: 5/100
Was this score accurate? 👍 Yes · 👎 No Scored by GitVelocity · How are scores calculated? |
dcschreiber
approved these changes
Sep 17, 2026
📊 Code Quality Score: 12/100
Was this score accurate? 👍 Yes · 👎 No Scored by GitVelocity · How are scores calculated? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Problem: Scrolling the reader while a translation is open in the resources panel crashes the app.
Fix 1 is the crash. Fixes 2 and 3 are in the same PR on purpose — Fix 2 is the other half of the commit that caused the crash, and Fix 3 is not optional once Fix 2 lands. See Why fixes 2 and 3 belong here for the reasoning.
1st Bug Description
When you open a translation,
VersionBlock.js:153creates aVersionFilterobject:When you then scroll to a new segment,
updateVersionCatre-pointed that filter at the new ref like this:{...obj}copies the object's own fields, butlistKey()lives onVersionFilter's prototype, not on the instance — so the spread silently drops it.ConnectionsPanelHeader.js:139then doeskey={filter.listKey()}on the next render and throws.This was introduced in 108b0d1, which replaced an in-place mutation with the spread.
Fix 1 — build a real
VersionFilter(ReaderApp.js:1458)Same data, but it's an actual class instance, so
listKey()/toString()/equals()still exist.Why fixes 2 and 3 belong in this PR
Fix 2 is the other half of the commit that caused Bug 1
108b0d15(May 2025) was a single refactor with one goal: stop mutating state inReaderApp.js. Two functions update the same "recent filters" arrays, and the refactor got each one wrong in a different way:updateVersionCat{...filter}— the one copy that drops class methodsopenFiltergit show 108b0d15never mentionsopenFilter)So Fix 2 isn't an unrelated cleanup we noticed in passing. It's the same defect, in the same file, from the same commit, on the same data structure — one function was converted incorrectly, the other wasn't converted at all. Fixing only the first leaves the refactor half-done in exactly the place that produced the bug.
Fix 3 is forced by Fix 2, and is the reason they can't be split
The wrong key name predates
6f189a50(Feb 2018), so it sat there for roughly seven years causing no harm. That's because Fix 2's bug was masking it:unshifthad already written the correct array into state beforesetStateran, sosetStatewriting to the wrong key simply didn't matter — the right key was already correct.Remove the mutation and
setStatebecomes the only thing writing that array. The wrong key stops being cosmetic:ConnectionsPanel.js:126then evaluatesrecentFilters[filterIndex].categorywith no guard for an empty array, which throws. Fix 2 without Fix 3 would be strictly worse than shipping neither — it trades one crash for another. They have to land together.If you'd prefer a minimal PR
Fix 1 stands completely on its own and resolves the reported crash. Dropping Fixes 2 and 3 together is a coherent option. Dropping only Fix 3 is not.
Fix 2 — stop mutating state in
openFilter(ReaderApp.js:1276)openFiltergrabbed the array straight out of state:Now it copies first:
Side benefit: two
!==checks that were dead now work, because the array is a new object each time.TextList.js:70comparesthis.props.recentFilters !== prevProps.recentFiltersto decide whether to rebuild its list, andReaderApp.js:436uses the same comparison to fire an analytics pageview. Both were alwaysfalsebefore.Fix 3 — write to the state key the app actually reads (ReaderApp.js:1309)
The panel renders
this.state.linkRecentFilters(ReaderApp.js:2199); nothing readsthis.state.recentFilters. Concretely, tapping Rashi used to leave state like:Fix 3 is required by Fix 2. Link filters were working by accident: the old
unshifthad already mutatedlinkRecentFiltersbeforesetStateran, so the wrong key never mattered. Once Fix 2 removes the mutation,setStateis the only thing writing the array — so without Fix 3,this.state.linkRecentFiltersstays empty andConnectionsPanel.js:126throws onrecentFilters[filterIndex].category.🤖 Generated with Claude Code