diff --git a/lib/reducers/entry-reducer.js b/lib/reducers/entry-reducer.js
--- a/lib/reducers/entry-reducer.js
+++ b/lib/reducers/entry-reducer.js
@@ -45,6 +45,7 @@
   serverEntryInfosObject,
 } from '../shared/entry-utils.js';
 import { threadInFilterList } from '../shared/thread-utils.js';
+import { updateSpecs } from '../shared/updates/update-specs.js';
 import type {
   RawEntryInfo,
   EntryStore,
@@ -64,7 +65,6 @@
   incrementalStateSyncActionType,
 } from '../types/socket-types.js';
 import { type RawThreadInfo } from '../types/thread-types.js';
-import { updateTypes } from '../types/update-types-enum.js';
 import {
   type ClientUpdateInfo,
   processUpdatesActionType,
@@ -646,25 +646,16 @@
   entryInfos: $ReadOnlyArray<RawEntryInfo>,
   newUpdates: $ReadOnlyArray<ClientUpdateInfo>,
 ): RawEntryInfo[] {
-  const entryIDs = new Set(entryInfos.map(entryInfo => entryInfo.id));
+  const entryIDs = new Set(
+    entryInfos.map(entryInfo => entryInfo.id).filter(Boolean),
+  );
   const mergedEntryInfos = [...entryInfos];
   for (const updateInfo of newUpdates) {
-    if (updateInfo.type === updateTypes.JOIN_THREAD) {
-      for (const entryInfo of updateInfo.rawEntryInfos) {
-        if (entryIDs.has(entryInfo.id)) {
-          continue;
-        }
-        mergedEntryInfos.push(entryInfo);
-        entryIDs.add(entryInfo.id);
-      }
-    } else if (updateInfo.type === updateTypes.UPDATE_ENTRY) {
-      const { entryInfo } = updateInfo;
-      if (entryIDs.has(entryInfo.id)) {
-        continue;
-      }
-      mergedEntryInfos.push(entryInfo);
-      entryIDs.add(entryInfo.id);
-    }
+    updateSpecs[updateInfo.type].mergeEntryInfos?.(
+      entryIDs,
+      mergedEntryInfos,
+      updateInfo,
+    );
   }
   return mergedEntryInfos;
 }
diff --git a/lib/shared/updates/join-thread-spec.js b/lib/shared/updates/join-thread-spec.js
--- a/lib/shared/updates/join-thread-spec.js
+++ b/lib/shared/updates/join-thread-spec.js
@@ -3,6 +3,7 @@
 import _isEqual from 'lodash/fp/isEqual.js';
 
 import type { UpdateSpec } from './update-spec.js';
+import type { RawEntryInfo } from '../../types/entry-types.js';
 import type { RawThreadInfos } from '../../types/thread-types.js';
 import type { ThreadJoinUpdateInfo } from '../../types/update-types.js';
 
@@ -24,4 +25,18 @@
       },
     ];
   },
+  mergeEntryInfos(
+    entryIDs: Set<string>,
+    mergedEntryInfos: Array<RawEntryInfo>,
+    update: ThreadJoinUpdateInfo,
+  ) {
+    for (const entryInfo of update.rawEntryInfos) {
+      const entryID = entryInfo.id;
+      if (!entryID || entryIDs.has(entryID)) {
+        continue;
+      }
+      mergedEntryInfos.push(entryInfo);
+      entryIDs.add(entryID);
+    }
+  },
 });
diff --git a/lib/shared/updates/update-entry-spec.js b/lib/shared/updates/update-entry-spec.js
--- a/lib/shared/updates/update-entry-spec.js
+++ b/lib/shared/updates/update-entry-spec.js
@@ -1,6 +1,21 @@
 // @flow
 
 import type { UpdateSpec } from './update-spec.js';
+import type { RawEntryInfo } from '../../types/entry-types.js';
 import type { EntryUpdateInfo } from '../../types/update-types.js';
 
-export const updateEntrySpec: UpdateSpec<EntryUpdateInfo> = Object.freeze({});
+export const updateEntrySpec: UpdateSpec<EntryUpdateInfo> = Object.freeze({
+  mergeEntryInfos(
+    entryIDs: Set<string>,
+    mergedEntryInfos: Array<RawEntryInfo>,
+    update: EntryUpdateInfo,
+  ) {
+    const { entryInfo } = update;
+    const entryID = entryInfo.id;
+    if (!entryID || entryIDs.has(entryID)) {
+      return;
+    }
+    mergedEntryInfos.push(entryInfo);
+    entryIDs.add(entryID);
+  },
+});
diff --git a/lib/shared/updates/update-spec.js b/lib/shared/updates/update-spec.js
--- a/lib/shared/updates/update-spec.js
+++ b/lib/shared/updates/update-spec.js
@@ -1,6 +1,7 @@
 // @flow
 
 import type { ThreadStoreOperation } from '../../ops/thread-store-ops.js';
+import type { RawEntryInfo } from '../../types/entry-types.js';
 import type { RawThreadInfos } from '../../types/thread-types.js';
 import type { ClientUpdateInfo } from '../../types/update-types.js';
 
@@ -9,4 +10,9 @@
     storeThreadInfos: RawThreadInfos,
     update: UpdateInfo,
   ) => ?$ReadOnlyArray<ThreadStoreOperation>,
+  +mergeEntryInfos?: (
+    entryIDs: Set<string>,
+    mergedEntryInfos: Array<RawEntryInfo>,
+    update: UpdateInfo,
+  ) => void,
 };