Skip to content

fix: White screen after deleting a tag#340

Open
katsyuta wants to merge 5 commits into
DeepinkApp:masterfrom
katsyuta:339-bug-white-screen-after-deleting-a-tag
Open

fix: White screen after deleting a tag#340
katsyuta wants to merge 5 commits into
DeepinkApp:masterfrom
katsyuta:339-bug-white-screen-after-deleting-a-tag

Conversation

@katsyuta

@katsyuta katsyuta commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

Closes: #339

Problem:
After deleting a tag the tags list in Redux is updated, triggering a new render. But the tags tree is rebuilt later in useEffect, so VirtualTagsList renders using an old tree that still contains the deleted tag. As a result, the component tries to load data for the deleted item by looking up its id in the tags list, but the tag not exists, so the lookup returns undefined

Solution:
Rebuild the tags tree before rendering the child component so it always renders with the latest tree state

Summary by CodeRabbit

Summary by CodeRabbit

  • Bug Fixes
    • Improved the Tags panel so the tag tree updates immediately when tag data changes.
    • Resolved cases where the displayed tree could lag behind the latest tags after the list was updated.

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c27594aa-bd48-4d5d-a6ab-d1ce809c3e58

📥 Commits

Reviewing files that changed from the base of the PR and between f64a812 and 2d18f8e.

📒 Files selected for processing (1)
  • packages/app/src/features/MainScreen/TagsPanel/TagsTree.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/app/src/features/MainScreen/TagsPanel/TagsTree.tsx

📝 Walkthrough

Walkthrough

The tree rebuild logic in TagsTree.tsx now runs synchronously during render when the tags reference changes, replacing the previous post-render useEffect trigger.

Changes

Tag Tree Rebuild Fix

Layer / File(s) Summary
In-render tree rebuild
packages/app/src/features/MainScreen/TagsPanel/TagsTree.tsx
Replaces useEffect(() => tree.rebuildTree(), [tags, tree]) with a useRef-tracked previous tags reference that triggers tree.rebuildTree() synchronously during render when the tags reference changes, and removes the now-unused useEffect import.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main bug fix: the white screen after deleting a tag.
Linked Issues check ✅ Passed The change addresses #339 by rebuilding the tags tree before render, preventing stale data and the reported white screen.
Out of Scope Changes check ✅ Passed The PR appears scoped to the tag-deletion rendering bug and does not introduce unrelated changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@katsyuta katsyuta marked this pull request as ready for review July 5, 2026 13:02
@katsyuta katsyuta requested a review from vitonsky July 5, 2026 13:06
@vitonsky

vitonsky commented Jul 5, 2026

Copy link
Copy Markdown
Member

@katsyuta could you update pull request description to explain in one paragraph what is the root cause of the problem and how this changes fix that problem.

@katsyuta

katsyuta commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author

@vitonsky, description is ready

Comment on lines +123 to +126
const prevTagsRef = useRef(tags);
if (prevTagsRef.current !== tags) {
prevTagsRef.current = tags;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How it does work?

  1. How to trigger first tree build? At first render this condition will not be passed
  2. Why not to use useMemo?
  3. Originally the deps is [tags, tree], why we depend on tags only now?

@katsyuta katsyuta Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1. tree.rebuildTree() is only needed when the source data changes. The initial tree build is triggered inside useTree with the actual data
2. I don't now how useMemo would help here, the only requirement is to ensure that rebuild is called after tags change and before child components are rendered
3. As i understand, tree was in the dependencies because it was just an esLint requirement. tree is a stable instance created by useTree, the rebuild is only required when the data is changed

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure rebuildTree can be called while rendering?

In case that call would start another render we may have problem, because such logic must not be run while rendering. Why this logic is wrapped via useEffect for now? Maybe just to run it after rendering, i don't know. Check it.

I don't now how useMemo would help here, the only requirement is to ensure that rebuild is called after tags change and before child components are rendered

React components must looks declarative. Don't write imperative code in component body. Invent some hook for that logic or search for NPM.

@katsyuta katsyuta Jul 7, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling rebuildTree trigger a re-render, but with the guard it is safe - no infinite loop.
When state updates during render, React re-renders that same component immediately, before rendering its children, within the same render cycle.
I wrap this logic to hook

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@katsyuta as I understand, the re-render call while run another render is unsafe and can throw errors by itself.

The problem is not in infinite loop. I saw errors about that, but I don't remember exactly why that's bad. Research that

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the react docs, they write about the pattern that i suggested.
If the state belonging to the component itself is updated, no error will occur. Under the hood, useTree uses a state to trigger a render, so when rebuildTree is called we update the state owned by the component itself

As i understand, the error can occur if update a different component while rendering. I found a some issue about this.

@katsyuta katsyuta requested a review from vitonsky July 6, 2026 22:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: White screen after deleting a tag

2 participants