Compare commits

...

3 commits

Author SHA1 Message Date
infinite-persistence
dc961b98ac
CommentReactions: optimize othersReacts selection
One solution is to apply the same factory method used in `Comments` to memoize the selector for each key. Unfortunately, I'm not sure how to re-use the same factory for both `Comments` and `CommentReactions`, so we will be memoizing it twice. This feels a bit dumb.

Since `CommentReactions` is almost-always** a child of `Comments` and using the same comment key, just get the calculated value from the parent through an optional prop.

** notifications uses it too, but I guess we can be inefficient there since it's not a component that's constantly updating.
2021-10-05 15:59:14 +08:00
infinite-persistence
875128fc94
Comment: fix memoization for multi-instance selector.
Since each comment will have a different key (and on other components, `props.uri` will differ), the selector cache won't work since the inputs keep changing.

The suggested solution is to apply a factory method wrap the selector -- this produces a unique memoized selector for each instance.
2021-10-05 15:58:30 +08:00
infinite-persistence
ad5af98417
makeSelectOthersReactionsForComment: fix memoization
`selectState` will always change we when update the state in the reducer, regardless of which field (sub-state) was updated. So, it shouldn't be used as the input for `createSelector`.
2021-10-05 15:53:18 +08:00
4 changed files with 34 additions and 24 deletions

View file

@ -19,24 +19,30 @@ import { selectActiveChannelClaim } from 'redux/selectors/app';
import { selectPlayingUri } from 'redux/selectors/content';
import Comment from './view';
const select = (state, props) => {
const activeChannelClaim = selectActiveChannelClaim(state);
const makeMapStateToProps = (originalState, originalProps) => {
const activeChannelClaim = selectActiveChannelClaim(originalState);
const activeChannelId = activeChannelClaim && activeChannelClaim.claim_id;
const reactionKey = activeChannelId ? `${props.commentId}:${activeChannelId}` : props.commentId;
const reactionKey = activeChannelId ? `${originalProps.commentId}:${activeChannelId}` : originalProps.commentId;
const selectOthersReactionsForComment = makeSelectOthersReactionsForComment(reactionKey);
return {
claim: makeSelectClaimForUri(props.uri)(state),
thumbnail: props.authorUri && makeSelectThumbnailForUri(props.authorUri)(state),
channelIsBlocked: props.authorUri && makeSelectChannelIsMuted(props.authorUri)(state),
commentingEnabled: IS_WEB ? Boolean(selectUserVerifiedEmail(state)) : true,
othersReacts: makeSelectOthersReactionsForComment(reactionKey)(state),
activeChannelClaim,
myChannels: selectMyChannelClaims(state),
playingUri: selectPlayingUri(state),
stakedLevel: makeSelectStakedLevelForChannelUri(props.authorUri)(state),
linkedCommentAncestors: selectLinkedCommentAncestors(state),
totalReplyPages: makeSelectTotalReplyPagesForParentId(props.commentId)(state),
const select = (state, props) => {
const othersReacts = selectOthersReactionsForComment(state);
return {
claim: makeSelectClaimForUri(props.uri)(state),
thumbnail: props.authorUri && makeSelectThumbnailForUri(props.authorUri)(state),
channelIsBlocked: props.authorUri && makeSelectChannelIsMuted(props.authorUri)(state),
commentingEnabled: IS_WEB ? Boolean(selectUserVerifiedEmail(state)) : true,
othersReacts,
activeChannelClaim,
myChannels: selectMyChannelClaims(state),
playingUri: selectPlayingUri(state),
stakedLevel: makeSelectStakedLevelForChannelUri(props.authorUri)(state),
linkedCommentAncestors: selectLinkedCommentAncestors(state),
totalReplyPages: makeSelectTotalReplyPagesForParentId(props.commentId)(state),
};
};
return select;
};
const perform = (dispatch) => ({
@ -47,4 +53,4 @@ const perform = (dispatch) => ({
doToast: (options) => dispatch(doToast(options)),
});
export default connect(select, perform)(Comment);
export default connect(makeMapStateToProps, perform)(Comment);

View file

@ -361,7 +361,9 @@ function Comment(props: Props) {
icon={ICONS.REPLY}
/>
)}
{ENABLE_COMMENT_REACTIONS && <CommentReactions uri={uri} commentId={commentId} />}
{ENABLE_COMMENT_REACTIONS && (
<CommentReactions uri={uri} commentId={commentId} othersReacts={othersReacts} />
)}
</div>
)}

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux';
import Comment from './view';
import CommentReactions from './view';
import { makeSelectClaimIsMine, makeSelectClaimForUri, doResolveUri } from 'lbry-redux';
import { doToast } from 'redux/actions/notifications';
import { makeSelectMyReactionsForComment, makeSelectOthersReactionsForComment } from 'redux/selectors/comments';
@ -15,7 +15,7 @@ const select = (state, props) => {
claim: makeSelectClaimForUri(props.uri)(state),
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
myReacts: makeSelectMyReactionsForComment(reactionKey)(state),
othersReacts: makeSelectOthersReactionsForComment(reactionKey)(state),
othersReacts: props.othersReacts || makeSelectOthersReactionsForComment(reactionKey)(state),
activeChannelId,
};
};
@ -26,4 +26,4 @@ const perform = (dispatch) => ({
doToast: (params) => dispatch(doToast(params)),
});
export default connect(select, perform)(Comment);
export default connect(select, perform)(CommentReactions);

View file

@ -5,6 +5,8 @@ import { selectShowMatureContent } from 'redux/selectors/settings';
import { selectBlacklistedOutpointMap, selectFilteredOutpointMap } from 'lbryinc';
import { selectClaimsById, isClaimNsfw, selectMyActiveClaims } from 'lbry-redux';
type State = { comments: CommentsState };
const selectState = (state) => state.comments || {};
export const selectCommentsById = createSelector(selectState, (state) => state.commentById || {});
@ -13,7 +15,7 @@ export const selectIsFetchingCommentsById = createSelector(selectState, (state)
export const selectIsFetchingCommentsByParentId = createSelector(selectState, (state) => state.isLoadingByParentId);
export const selectIsPostingComment = createSelector(selectState, (state) => state.isCommenting);
export const selectIsFetchingReacts = createSelector(selectState, (state) => state.isFetchingReacts);
export const selectOthersReactsById = createSelector(selectState, (state) => state.othersReactsByCommentId);
export const selectOthersReactsById = (state: State) => state.comments.othersReactsByCommentId;
export const selectPinnedCommentsById = createSelector(selectState, (state) => state.pinnedCommentsById);
export const makeSelectPinnedCommentsForUri = (uri: string) =>
@ -191,12 +193,12 @@ export const makeSelectMyReactionsForComment = (commentIdChannelId: string) =>
});
export const makeSelectOthersReactionsForComment = (commentId: string) =>
createSelector(selectState, (state) => {
if (!state.othersReactsByCommentId) {
createSelector(selectOthersReactsById, (othersReactsByCommentId) => {
if (!othersReactsByCommentId) {
return {};
}
return state.othersReactsByCommentId[commentId] || {};
return othersReactsByCommentId[commentId] || {};
});
export const selectPendingCommentReacts = createSelector(selectState, (state) => state.pendingCommentReactions);