From 382c9ef1bc1b16cc3f3762bd73ebca1571163a72 Mon Sep 17 00:00:00 2001 From: pimothyxd <29018740+pimothyxd@users.noreply.github.com> Date: Sat, 17 Feb 2024 02:28:07 +0100 Subject: [PATCH] fix(twitch): experiment category scroll (#980) Scrolling through the streams inside of a specific category can lock up after initial page load / while scrolling down. This issue seems to happen because the AvatarsModule patches and re-renders the avatars after updating their properties. However, it seems like during re-rendering it grabs a virtual node holding the cards where you actually scroll through. Updating that container (instead of it's parent holding it's ref) will cause simplebar to break and delete containers. Fixes #635 Co-authored-by: Troy --- CHANGELOG-nightly.md | 1 + .../modules/avatars/AvatarsModule.vue | 21 +++++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CHANGELOG-nightly.md b/CHANGELOG-nightly.md index 4245d10bb..c2516101b 100644 --- a/CHANGELOG-nightly.md +++ b/CHANGELOG-nightly.md @@ -3,6 +3,7 @@ **The changes listed here are not assigned to an official release**. - Reinstated animated avatars +- Fixed an issue which caused scrolling to not work while scrolling through a category - Fixed an issue where lowercase cheers were displayed as text - Added an option to hide the community challenge contributions in the chat - Fixed extension not working on twitch for some users (React 18 support) diff --git a/src/site/twitch.tv/modules/avatars/AvatarsModule.vue b/src/site/twitch.tv/modules/avatars/AvatarsModule.vue index d1408fbaf..d3f1d1164 100644 --- a/src/site/twitch.tv/modules/avatars/AvatarsModule.vue +++ b/src/site/twitch.tv/modules/avatars/AvatarsModule.vue @@ -4,7 +4,7 @@ import { onMounted, onUnmounted, reactive, ref, watch } from "vue"; import { watchDebounced } from "@vueuse/core"; import { ObserverPromise } from "@/common/Async"; -import { getVNodeFromDOM } from "@/common/ReactHooks"; +import { findComponentParents, getVNodeFromDOM } from "@/common/ReactHooks"; import { defineFunctionHook, unsetPropertyHook } from "@/common/Reflection"; import { db } from "@/db/idb"; import { declareModule } from "@/composable/useModule"; @@ -123,7 +123,20 @@ function doRerender() { } if (returnCom.stateNode) { - if ("forceUpdate" in returnCom.stateNode) { + // to avoid simplebar from breaking, we need to update the parent + // holding the ref instead. + if ("simplebarRef" in returnCom.stateNode) { + const [parent] = findComponentParents( + returnCom, + (component) => component.setRootScrollableContentRef !== undefined, + undefined, + 1, + ); + if (parent) { + componentsToForceUpdate.add(parent); + break; + } + } else if ("forceUpdate" in returnCom.stateNode) { componentsToForceUpdate.add(returnCom.stateNode); break; } @@ -134,7 +147,7 @@ function doRerender() { } for (const com of componentsToForceUpdate) { - for (let i = 0; i < 2; i++) com.forceUpdate(); + for (let i = 0; i < 2; ++i) com.forceUpdate(); } for (const [com, key] of oldKeys) { @@ -197,7 +210,7 @@ function assignAvatar(av: SevenTV.Cosmetic<"AVATAR">) { watchDebounced( avatars, () => { - doRerender(); + if (shouldRenderAvatars.value) doRerender(); }, { debounce: 350,