From f077110dec77c4f37cb52e242334f8508ae13f89 Mon Sep 17 00:00:00 2001 From: infinite-persistence Date: Tue, 5 Oct 2021 22:09:49 +0800 Subject: [PATCH] Skip muted list update if no change ## Issue Components render unnecessarily due to reference invalidation from `selectMutedChannels` selector. ## Notes `selectMutedChannels` run and return a new reference each time the app gains focus. `createSelector` will not help in this case, because we are indeed invalidating the data in the store in `USER_STATE_POPULATE`. ## Changes - Don't update the state if the array is identical in content. - Fixed `selectMutedChannels` to return the reference from the store, so `createSelector` is not needed. - Also, the filtering is not needed because we've already done it in the reducer. ## Comments I've done some profiling on large blocklists. The time needed for the array comparison is still an order magnitude lower than the time needed to render all the Components that got incorrectly marked by this. The ideal solution is for the sync code to return a hash or timestamp of the array, so that we can compare that instead of the array. --- ui/redux/reducers/blocked.js | 8 ++++++++ ui/redux/selectors/blocked.js | 8 ++++---- ui/redux/selectors/comments.js | 7 +++++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/ui/redux/reducers/blocked.js b/ui/redux/reducers/blocked.js index d2ab80763..449f61c92 100644 --- a/ui/redux/reducers/blocked.js +++ b/ui/redux/reducers/blocked.js @@ -30,6 +30,14 @@ export default handleActions( ) => { const { blocked } = action.data; const sanitizedBlocked = blocked && blocked.filter((e) => typeof e === 'string'); + + const next = sanitizedBlocked; + const prev = state.blockedChannels; + + if (next && prev && prev.length === next.length && prev.every((value, index) => value === next[index])) { + return state; + } + return { ...state, blockedChannels: sanitizedBlocked && sanitizedBlocked.length ? sanitizedBlocked : state.blockedChannels, diff --git a/ui/redux/selectors/blocked.js b/ui/redux/selectors/blocked.js index 2eca07d52..f7f0d3de6 100644 --- a/ui/redux/selectors/blocked.js +++ b/ui/redux/selectors/blocked.js @@ -2,11 +2,11 @@ import { createSelector } from 'reselect'; import { splitBySeparator } from 'lbry-redux'; -const selectState = (state: { blocked: BlocklistState }) => state.blocked || {}; +type State = { blocked: BlocklistState }; -export const selectMutedChannels = createSelector(selectState, (state: BlocklistState) => { - return state.blockedChannels.filter((e) => typeof e === 'string'); -}); +const selectState = (state: State) => state.blocked || {}; + +export const selectMutedChannels = (state: State) => selectState(state).blockedChannels; export const makeSelectChannelIsMuted = (uri: string) => createSelector(selectMutedChannels, (state: Array) => { diff --git a/ui/redux/selectors/comments.js b/ui/redux/selectors/comments.js index e19e236f4..40139e1c2 100644 --- a/ui/redux/selectors/comments.js +++ b/ui/redux/selectors/comments.js @@ -36,8 +36,11 @@ export const makeSelectPinnedCommentsForUri = (uri: string) => } ); -export const selectModerationBlockList = createSelector(selectState, (state) => - state.moderationBlockList ? state.moderationBlockList.reverse() : [] +export const selectModerationBlockList = createSelector( + (state) => selectState(state).moderationBlockList, + (moderationBlockList) => { + return moderationBlockList ? moderationBlockList.reverse() : []; + } ); export const selectAdminBlockList = createSelector(selectState, (state) => state.adminBlockList ? state.adminBlockList.reverse() : []