Skip to content

refactor(RoomView): observe the followed thread through useSyncExternalStore - #7634

Merged
diegolmello merged 1 commit into
native-34-roomview-hooksfrom
diegolmello/useThreadFollowing-useSyncExternalStore
Sep 2, 2026
Merged

refactor(RoomView): observe the followed thread through useSyncExternalStore#7634
diegolmello merged 1 commit into
native-34-roomview-hooksfrom
diegolmello/useThreadFollowing-useSyncExternalStore

Conversation

@diegolmello

@diegolmello diegolmello commented Sep 2, 2026

Copy link
Copy Markdown
Member

Proposed changes

useThreadFollowing fetched the thread message once with getMessageById, then subscribed to the record inside a useEffect and mirrored it into useState. It now builds a WatermelonDB query observable in render and reads it through a new useObservable hook backed by useSyncExternalStore.

  • useObservable(observable) in lib/hooks bridges any rxjs observable to React. It keys the cached emission by source, so a changed observable returns undefined until the new source emits instead of the previous source's value.
  • The thread query uses observeWithColumns(['replies']), so the follow state re-emits when replies changes on the already-matched record. A plain observe() on a query only re-emits when the matching set changes.
  • userId is no longer a subscription dependency; the follow check is derived in render.

Issue(s)

Follow-up to #7482

How to test or reproduce

  1. Open a thread you have not replied to. The header shows the follow icon.
  2. Follow the thread from the header. The icon flips to unfollow without leaving the screen.
  3. Reply in the thread from another client. The icon flips to unfollow.
  4. Navigate between two threads with different follow states. The icon reflects the current thread, never the previous one.

Screenshots

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • Improvement (non-breaking change which improves a current function)
  • New feature (non-breaking change which adds functionality)
  • Documentation update (if none of the other choices apply)

Checklist

  • I have read the CONTRIBUTING doc
  • I have signed the CLA
  • Lint and unit tests pass locally with my changes
  • I have added tests that prove my fix is effective or that my feature works (if applicable)
  • I have added necessary documentation (if applicable)
  • Any dependent changes have been merged and published in downstream modules

Further comments

Open questions kept out of this PR: whether useObservable should stay generic with a single caller or be inlined, whether the query belongs in lib/database/services/Message as observeMessageById, and whether a deleted thread record should report "following" (current behaviour) or something else.

Summary by CodeRabbit

  • Bug Fixes

    • Improved thread-following status updates by responding to reply changes more reliably.
    • Ensured thread-following state handles unavailable threads and missing replies correctly.
  • Tests

    • Added coverage for observable values, source changes, cleanup, and empty inputs.
    • Expanded thread-following tests to cover reply updates and threads without replies.

@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: d0a34034-973e-442b-97dc-89f1872dd8c5

📥 Commits

Reviewing files that changed from the base of the PR and between be5b0b0 and 0198587.

📒 Files selected for processing (4)
  • app/lib/hooks/__tests__/useObservable.test.ts
  • app/lib/hooks/useObservable.ts
  • app/views/RoomView/hooks/__tests__/useThreadFollowing.test.ts
  • app/views/RoomView/hooks/useThreadFollowing.ts

Walkthrough

The PR adds the useObservable hook and tests. It updates useThreadFollowing to consume a WatermelonDB query observable for replies, with synchronous test coverage for emissions, missing threads, observed columns, and cleanup.

Changes

Observable thread-following

Layer / File(s) Summary
Add useObservable hook
app/lib/hooks/useObservable.ts, app/lib/hooks/__tests__/useObservable.test.ts
The hook tracks the latest emission, resets values when the observable changes, supports an absent observable, and unsubscribes during cleanup. Tests cover these behaviors.
Integrate thread-following observation
app/views/RoomView/hooks/useThreadFollowing.ts, app/views/RoomView/hooks/__tests__/useThreadFollowing.test.ts
useThreadFollowing now observes the thread query’s replies column and evaluates emitted thread records. Tests use synchronous emissions and verify missing threads, reply states, column observation, and unmount behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested labels: type: bug

Sequence Diagram(s)

sequenceDiagram
  participant useThreadFollowing
  participant WatermelonDBQuery
  participant useObservable
  useThreadFollowing->>WatermelonDBQuery: observeWithColumns replies
  WatermelonDBQuery-->>useObservable: emit thread records
  useObservable-->>useThreadFollowing: return latest thread
  useThreadFollowing-->>useThreadFollowing: evaluate userId in replies
Loading

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.

@diegolmello
diegolmello merged commit e9d971f into native-34-roomview-hooks Sep 2, 2026
5 of 7 checks passed
@diegolmello
diegolmello deleted the diegolmello/useThreadFollowing-useSyncExternalStore branch September 2, 2026 17:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant