Replaces the previous mirrored localCount / localLike useState with derived
values computed from `post.likesCount` / `post.userLike` plus the existing
optimisticLikes entry from the community store. The local-state mirror was
the root cause of two separate bugs:
1. Foreign likes never reflected — useState seeded once from props on mount,
so the React-Query cache patch in useCommunityRealtime updated the prop
but the displayed count stayed frozen at the mount value.
2. The earlier sync-via-useEffect attempt (4c4792c, reverted in ab9472b)
broke own-likes because clearing optimistic state could happen before
the cache patch landed, so useEffect re-read a stale `post.likesCount`
and snapped the count back down — visible as a 2 → 1 → 2 flicker on tap,
and as the heart staying red after a toggle-off.
The fix is to NOT mirror at all. The store's `optimisticLikes` map already
stores `{ delta, userLike }` per post (it was set but never read before).
Render path now:
displayedLike = optimistic?.userLike ?? (post.userLike === 'like' ? 'like' : null)
displayedCount = (post.likesCount ?? 0) + (optimistic?.delta ?? 0)
In handleLike, after the API responds, the React-Query cache is patched
synchronously with the server-truth response before clearOptimisticLike
runs — so the moment the delta drops to 0, the prop already reflects the
new count. No race window, no useEffect, no own/foreign distinction needed.
`isLiking` is still kept as a re-tap guard against double-tap-mid-flight.
`useCommunityRealtime` was already patching the React-Query cache
on community_posts UPDATE events — likesCount, dislikesCount, userLike
all reached the component as props on re-render. But PostCard was
seeding `localLike` / `localCount` once via useState initial values
and never re-reading the props after mount, so a like from another
account showed up as a notification but the heart counter stayed
stale until pull-to-refresh.
Added a useEffect that mirrors `post.likesCount` / `post.userLike`
back into local state, guarded by `isLiking` so an in-flight
optimistic update isn't clobbered by a concurrent realtime patch
of the same row.
Handles unlike (decrement) on the same path, plus off-screen posts
which get the patched cache value on remount and feed-list cards
that refresh in place without scroll.
Alle <Pressable style={({pressed}) => ({...})}> ersetzt — style-Funktion
droppt auf Android (New Arch) intermittierend width/height, führt zu 0×0
unsichtbaren Elementen. TouchableOpacity mit activeOpacity ist stabil.
Außerdem übrige Pressables (plain style) aus components/ und app/
migriert sowie zwei überschüssige </View>-Tags in chat.tsx + RoomCard.tsx
entfernt die TS-Fehler verursacht haben.
64 Dateien, typecheck sauber.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>