Cache the processing of ChannelMentionSuggestions (#309)

## Issue
One of the bottlenecks of livestream page.

The component probably needs a re-design:
- Don't perpetually mount -- only mount when activated by the user through "@". This would avoid the heavy processing entirely.
- Better way of resolving uris (too many arrays, too many loops).
- Tom also mentioned that we should not be resolving every commenter as we see encounter them in a livestream. This is currently the case because the component is always mounted.

## Changes
Until the re-design occurs, attempt to cache the heavy processing. Also, trimmed down the amount of loops.
This commit is contained in:
infinite-persistence 2021-11-17 08:47:56 -08:00 committed by GitHub
parent 47c316e0ad
commit e35069de1c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 78 additions and 27 deletions

View file

@ -3,38 +3,23 @@ import { MAX_LIVESTREAM_COMMENTS } from 'constants/livestream';
import { selectShowMatureContent } from 'redux/selectors/settings';
import { selectSubscriptionUris } from 'redux/selectors/subscriptions';
import { withRouter } from 'react-router';
import { makeSelectClaimForUri } from 'redux/selectors/claims';
import { selectCanonicalUrlForUri } from 'redux/selectors/claims';
import { doResolveUris } from 'redux/actions/claims';
import { selectTopLevelCommentsForUri } from 'redux/selectors/comments';
import { selectChannelMentionData } from 'redux/selectors/livestream';
import ChannelMentionSuggestions from './view';
const select = (state, props) => {
const subscriptionUris = selectSubscriptionUris(state);
const topLevelComments = selectTopLevelCommentsForUri(
state,
props.uri,
props.isLivestream ? MAX_LIVESTREAM_COMMENTS : -1
);
const commentorUris = [];
// Avoid repeated commentors
topLevelComments.map(({ channel_url }) => !commentorUris.includes(channel_url) && commentorUris.push(channel_url));
const getUnresolved = (uris) =>
uris.map((uri) => !makeSelectClaimForUri(uri)(state) && uri).filter((uri) => uri !== false);
const getCanonical = (uris) =>
uris
.map((uri) => makeSelectClaimForUri(uri)(state) && makeSelectClaimForUri(uri)(state).canonical_url)
.filter((uri) => Boolean(uri));
const maxComments = props.isLivestream ? MAX_LIVESTREAM_COMMENTS : -1;
const data = selectChannelMentionData(state, props.uri, maxComments);
return {
commentorUris,
subscriptionUris,
unresolvedCommentors: getUnresolved(commentorUris),
unresolvedSubscriptions: getUnresolved(subscriptionUris),
canonicalCreator: getCanonical([props.creatorUri])[0],
canonicalCommentors: getCanonical(commentorUris),
canonicalSubscriptions: getCanonical(subscriptionUris),
commentorUris: data.commentorUris,
subscriptionUris: selectSubscriptionUris(state),
unresolvedCommentors: data.unresolvedCommentors,
unresolvedSubscriptions: data.unresolvedSubscriptions,
canonicalCreator: selectCanonicalUrlForUri(state, props.creatorUri),
canonicalCommentors: data.canonicalCommentors,
canonicalSubscriptions: data.canonicalSubscriptions,
showMature: selectShowMatureContent(state),
};
};

View file

@ -1,7 +1,9 @@
// @flow
import { createSelector } from 'reselect';
import { createCachedSelector } from 're-reselect';
import { selectMyClaims, selectPendingClaims } from 'redux/selectors/claims';
import { selectMyClaims, selectPendingClaims, selectClaimIdsByUri, selectClaimsById } from 'redux/selectors/claims';
import { selectTopLevelCommentsForUri } from 'redux/selectors/comments';
import { selectSubscriptionUris } from 'redux/selectors/subscriptions';
type State = { livestream: any };
@ -61,3 +63,67 @@ export const selectIsActiveLivestreamForUri = createCachedSelector(
return activeLivestreamValues.some((v) => v.latestClaimUri === uri);
}
)((state, uri) => String(uri));
// ****************************************************************************
// Temporary
// ****************************************************************************
// Until ChannelMentions is redesigned, this serves as a cached and leaner
// version of the original code.
export const selectChannelMentionData = createCachedSelector(
selectClaimIdsByUri,
selectClaimsById,
selectTopLevelCommentsForUri,
selectSubscriptionUris,
(claimIdsByUri, claimsById, topLevelComments, subscriptionUris) => {
const commentorUris = [];
const unresolvedCommentors = [];
const unresolvedSubscriptions = [];
const canonicalCommentors = [];
const canonicalSubscriptions = [];
topLevelComments.forEach((comment) => {
const uri = comment.channel_url;
if (!commentorUris.includes(uri)) {
// Update: commentorUris
commentorUris.push(uri);
// Update: unresolvedCommentors
const claimId = claimIdsByUri[uri];
if (claimId === undefined) {
unresolvedCommentors.push(uri);
}
// Update: canonicalCommentors
const claim = claimsById[claimId];
if (claim && claim.canonical_url) {
canonicalCommentors.push(claim.canonical_url);
}
}
});
subscriptionUris.forEach((uri) => {
// Update: unresolvedSubscriptions
const claimId = claimIdsByUri[uri];
if (claimId === undefined) {
unresolvedSubscriptions.push(uri);
}
// Update: canonicalSubscriptions
const claim = claimsById[claimId];
if (claim && claim.canonical_url) {
canonicalSubscriptions.push(claim.canonical_url);
}
});
return {
topLevelComments,
commentorUris,
unresolvedCommentors,
canonicalCommentors,
unresolvedSubscriptions,
canonicalSubscriptions,
};
}
)((state, uri, maxCount) => `${String(uri)}:${maxCount}`);