Use 'selectHasChannel' instead of the full 'selectMyChannelClaims'

- selectMyChannelClaims depends on `byId`, which currently is always invalidated per update, so it is not memoized.

- Most of the use-cases just needs the ID or the length of the array anyways, so avoid generating a Claim array (in selectMyChannelClaims) unnecessarily -- the client need to reduce it back down to IDs again :/

- The simpler boolean also removes the need to memoize the selector, which saves a bit of memory.
This commit is contained in:
infinite-persistence 2021-11-08 14:27:14 +08:00
parent 9c5fbe5521
commit 0f1d4039a9
No known key found for this signature in database
GPG key ID: B9C3252EDC3D0AA0
23 changed files with 51 additions and 69 deletions

View file

@ -3,7 +3,7 @@ import {
makeSelectStakedLevelForChannelUri,
makeSelectClaimForUri,
makeSelectThumbnailForUri,
selectMyChannelClaims,
selectHasChannels,
} from 'redux/selectors/claims';
import { doCommentUpdate, doCommentList } from 'redux/actions/comments';
import { makeSelectChannelIsMuted } from 'redux/selectors/blocked';
@ -31,7 +31,7 @@ const select = (state, props) => {
commentingEnabled: IS_WEB ? Boolean(selectUserVerifiedEmail(state)) : true,
othersReacts: selectOthersReactsForComment(state, reactionKey),
activeChannelClaim,
myChannels: selectMyChannelClaims(state),
hasChannels: selectHasChannels(state),
playingUri: selectPlayingUri(state),
stakedLevel: makeSelectStakedLevelForChannelUri(props.authorUri)(state),
linkedCommentAncestors: selectLinkedCommentAncestors(state),

View file

@ -49,7 +49,7 @@ type Props = {
commentModBlock: (string) => void,
linkedCommentId?: string,
linkedCommentAncestors: { [string]: Array<string> },
myChannels: ?Array<ChannelClaim>,
hasChannels: boolean,
commentingEnabled: boolean,
doToast: ({ message: string }) => void,
isTopLevel?: boolean,
@ -94,7 +94,7 @@ function Comment(props: Props) {
linkedCommentId,
linkedCommentAncestors,
commentingEnabled,
myChannels,
hasChannels,
doToast,
isTopLevel,
threadDepth,
@ -134,7 +134,6 @@ function Comment(props: Props) {
const [page, setPage] = useState(showRepliesOnMount ? 1 : 0);
const [advancedEditor] = usePersistedState('comment-editor-mode', false);
const [displayDeadComment, setDisplayDeadComment] = React.useState(false);
const hasChannels = myChannels && myChannels.length > 0;
const likesCount = (othersReacts && othersReacts.like) || 0;
const dislikesCount = (othersReacts && othersReacts.dislike) || 0;
const totalLikesAndDislikes = likesCount + dislikesCount;

View file

@ -2,7 +2,7 @@ import { connect } from 'react-redux';
import {
makeSelectClaimForUri,
makeSelectClaimIsMine,
selectMyChannelClaims,
selectHasChannels,
selectFetchingMyChannels,
makeSelectTagInClaimOrChannelForUri,
} from 'redux/selectors/claims';
@ -16,7 +16,7 @@ import { selectSettingsByChannelId } from 'redux/selectors/comments';
const select = (state, props) => ({
activeChannelClaim: selectActiveChannelClaim(state),
channels: selectMyChannelClaims(state),
hasChannels: selectHasChannels(state),
claim: makeSelectClaimForUri(props.uri)(state),
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
isFetchingChannels: selectFetchingMyChannels(state),

View file

@ -43,7 +43,7 @@ type Props = {
activeChannel: string,
activeChannelClaim: ?ChannelClaim,
bottom: boolean,
channels: ?Array<ChannelClaim>,
hasChannels: boolean,
claim: StreamClaim,
claimIsMine: boolean,
embed?: boolean,
@ -72,7 +72,7 @@ export function CommentCreate(props: Props) {
const {
activeChannelClaim,
bottom,
channels,
hasChannels,
claim,
claimIsMine,
embed,
@ -146,7 +146,6 @@ export function CommentCreate(props: Props) {
const claimId = claim && claim.claim_id;
const channelUri = claim && (claim.signing_channel ? claim.signing_channel.permanent_url : claim.permanent_url);
const hasChannels = channels && channels.length;
const charCount = commentValue ? commentValue.length : 0;
const disabled = deletedComment || isSubmitting || isFetchingChannels || !commentValue.length || pauseQuickSend;
const channelId = getChannelIdFromClaim(claim);

View file

@ -1,6 +1,6 @@
import { connect } from 'react-redux';
import { doResolveUris } from 'redux/actions/claims';
import { makeSelectClaimIsMine, selectMyChannelClaims, makeSelectClaimForUri } from 'redux/selectors/claims';
import { makeSelectClaimIsMine, selectMyChannelClaimIds, makeSelectClaimForUri } from 'redux/selectors/claims';
import { selectIsFetchingCommentsByParentId, selectRepliesForParentId } from 'redux/selectors/comments';
import { selectUserVerifiedEmail } from 'redux/selectors/user';
import CommentsReplies from './view';
@ -17,7 +17,7 @@ const select = (state, props) => {
resolvedReplies,
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
userCanComment: IS_WEB ? Boolean(selectUserVerifiedEmail(state)) : true,
myChannels: selectMyChannelClaims(state),
myChannelIds: selectMyChannelClaimIds(state),
isFetchingByParentId: selectIsFetchingCommentsByParentId(state),
};
};

View file

@ -11,7 +11,7 @@ type Props = {
uri: string,
parentId: string,
claimIsMine: boolean,
myChannels: ?Array<ChannelClaim>,
myChannelIds: ?Array<string>,
linkedCommentId?: string,
userCanComment: boolean,
threadDepth: number,
@ -30,7 +30,7 @@ function CommentsReplies(props: Props) {
fetchedReplies,
resolvedReplies,
claimIsMine,
myChannels,
myChannelIds,
linkedCommentId,
userCanComment,
threadDepth,
@ -95,11 +95,7 @@ function CommentsReplies(props: Props) {
message={comment.comment}
timePosted={comment.timestamp * 1000}
claimIsMine={claimIsMine}
commentIsMine={
comment.channel_id &&
myChannels &&
myChannels.some(({ claim_id }) => claim_id === comment.channel_id)
}
commentIsMine={comment.channel_id && myChannelIds && myChannelIds.includes(comment.channel_id)}
linkedCommentId={linkedCommentId}
commentingEnabled={userCanComment}
supportAmount={comment.support_amount}

View file

@ -2,7 +2,7 @@ import { connect } from 'react-redux';
import {
makeSelectClaimIsMine,
makeSelectClaimForUri,
selectMyChannelClaims,
selectHasChannels,
makeSelectClaimIsStreamPlaceholder,
makeSelectTagInClaimOrChannelForUri,
} from 'redux/selectors/claims';
@ -23,7 +23,7 @@ const select = (state, props) => ({
fileInfo: makeSelectFileInfoForUri(props.uri)(state),
renderMode: makeSelectFileRenderModeForUri(props.uri)(state),
costInfo: makeSelectCostInfoForUri(props.uri)(state),
myChannels: selectMyChannelClaims(state),
hasChannels: selectHasChannels(state),
isLivestreamClaim: makeSelectClaimIsStreamPlaceholder(props.uri)(state),
reactionsDisabled: makeSelectTagInClaimOrChannelForUri(props.uri, DISABLE_COMMENTS_TAG)(state),
streamingUrl: makeSelectStreamingUrlForUri(props.uri)(state),

View file

@ -27,7 +27,7 @@ type Props = {
fileInfo: FileListItem,
costInfo: ?{ cost: number },
renderMode: string,
myChannels: ?Array<ChannelClaim>,
hasChannels: boolean,
doToast: ({ message: string }) => void,
clearPlayingUri: () => void,
hideRepost?: boolean,
@ -47,7 +47,7 @@ function FileActions(props: Props) {
costInfo,
renderMode,
prepareEdit,
myChannels,
hasChannels,
clearPlayingUri,
doToast,
hideRepost,
@ -63,7 +63,6 @@ function FileActions(props: Props) {
const isMobile = useIsMobile();
const webShareable = costInfo && costInfo.cost === 0 && RENDER_MODES.WEB_SHAREABLE_MODES.includes(renderMode);
const showDelete = claimIsMine || (fileInfo && (fileInfo.written_bytes > 0 || fileInfo.blobs_completed > 0));
const hasChannels = myChannels && myChannels.length > 0;
const claimId = claim && claim.claim_id;
const { signing_channel: signingChannel } = claim;
const channelName = signingChannel && signingChannel.name;

View file

@ -15,7 +15,7 @@ import {
selectIsResolvingPublishUris,
selectMyClaimForUri,
} from 'redux/selectors/publish';
import { selectMyChannelClaims, makeSelectClaimIsStreamPlaceholder } from 'redux/selectors/claims';
import { makeSelectClaimIsStreamPlaceholder } from 'redux/selectors/claims';
import * as RENDER_MODES from 'constants/file_render_modes';
import * as SETTINGS from 'constants/settings';
import { doClaimInitialRewards } from 'redux/actions/rewards';
@ -33,7 +33,7 @@ import {
import { makeSelectClientSetting } from 'redux/selectors/settings';
import { makeSelectFileRenderModeForUri } from 'redux/selectors/content';
import { selectUser } from 'redux/selectors/user';
import PublishPage from './view';
import PublishForm from './view';
const select = (state) => {
const myClaimForUri = selectMyClaimForUri(state);
@ -61,7 +61,6 @@ const select = (state) => {
modal: selectModal(state),
enablePublishPreview: makeSelectClientSetting(SETTINGS.ENABLE_PUBLISH_PREVIEW)(state),
activeChannelClaim: selectActiveChannelClaim(state),
myChannels: selectMyChannelClaims(state),
incognito: selectIncognito(state),
activeChannelStakedLevel: selectActiveChannelStakedLevel(state),
isClaimingInitialRewards: selectIsClaimingInitialRewards(state),
@ -80,4 +79,4 @@ const perform = (dispatch) => ({
claimInitialRewards: () => dispatch(doClaimInitialRewards()),
});
export default connect(select, perform)(PublishPage);
export default connect(select, perform)(PublishForm);

View file

@ -3,7 +3,6 @@ import { doHideModal } from 'redux/actions/app';
import {
makeSelectClaimForUri,
makeSelectTitleForUri,
selectMyChannelClaims,
selectRepostError,
selectRepostLoading,
selectMyClaimsWithoutChannels,
@ -24,7 +23,6 @@ import { selectActiveChannelClaim, selectIncognito } from 'redux/selectors/app';
import RepostCreate from './view';
const select = (state, props) => ({
channels: selectMyChannelClaims(state),
claim: makeSelectClaimForUri(props.uri)(state),
passedRepostClaim: makeSelectClaimForUri(props.name, false)(state),
passedRepostAmount: makeSelectEffectiveAmountForUri(props.name)(state),

View file

@ -27,7 +27,6 @@ type Props = {
claim?: StreamClaim,
enteredContentClaim?: StreamClaim,
balance: number,
channels: ?Array<ChannelClaim>,
doCheckPublishNameAvailability: (string) => Promise<*>,
error: ?string,
reposting: boolean,

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux';
import { selectMyChannelClaims } from 'redux/selectors/claims';
import { selectHasChannels } from 'redux/selectors/claims';
import { selectWalletIsEncrypted } from 'redux/selectors/wallet';
import { doWalletStatus } from 'redux/actions/wallet';
import { selectUser, selectUserVerifiedEmail } from 'redux/selectors/user';
@ -11,7 +11,7 @@ const select = (state) => ({
isAuthenticated: selectUserVerifiedEmail(state),
walletEncrypted: selectWalletIsEncrypted(state),
user: selectUser(state),
myChannels: selectMyChannelClaims(state),
hasChannels: selectHasChannels(state),
language: selectLanguage(state),
});

View file

@ -11,17 +11,16 @@ import { getPasswordFromCookie } from 'util/saved-passwords';
import { getStripeEnvironment } from 'util/stripe';
type Props = {
// --- select ---
// --- redux ---
isAuthenticated: boolean,
walletEncrypted: boolean,
user: User,
myChannels: ?Array<ChannelClaim>,
// --- perform ---
hasChannels: boolean,
doWalletStatus: () => void,
};
export default function SettingAccount(props: Props) {
const { isAuthenticated, walletEncrypted, user, myChannels, doWalletStatus } = props;
const { isAuthenticated, walletEncrypted, user, hasChannels, doWalletStatus } = props;
const [storedPassword, setStoredPassword] = React.useState(false);
// Determine if password is stored.
@ -94,7 +93,7 @@ export default function SettingAccount(props: Props) {
)}
{/* @endif */}
{myChannels && (
{hasChannels && (
<SettingsRow title={__('Comments')} subtitle={__('View your past comments.')}>
<Button
button="inverse"

View file

@ -1,6 +1,6 @@
import { connect } from 'react-redux';
import { selectBalance } from 'redux/selectors/wallet';
import { selectMyChannelClaims, makeSelectClaimForUri } from 'redux/selectors/claims';
import { makeSelectClaimForUri } from 'redux/selectors/claims';
import { doOpenModal } from 'redux/actions/app';
import WalletSend from './view';
import { withRouter } from 'react-router';
@ -12,7 +12,6 @@ const perform = (dispatch) => ({
const select = (state, props) => ({
balance: selectBalance(state),
channels: selectMyChannelClaims(state),
contentClaim: makeSelectClaimForUri(props.contentUri)(state),
snack: selectToast(state),
});

View file

@ -1,10 +1,5 @@
import { connect } from 'react-redux';
import {
selectMyChannelClaims,
selectMyChannelUrls,
selectFetchingMyChannels,
makeSelectClaimIsPending,
} from 'redux/selectors/claims';
import { selectMyChannelUrls, selectFetchingMyChannels, makeSelectClaimIsPending } from 'redux/selectors/claims';
import { doFetchChannelListMine } from 'redux/actions/claims';
import { doSetActiveChannel } from 'redux/actions/app';
import { selectYoutubeChannels } from 'redux/selectors/user';
@ -22,7 +17,6 @@ const select = (state) => {
return {
channelUrls,
channels: selectMyChannelClaims(state),
fetchingChannels: selectFetchingMyChannels(state),
youtubeChannels: selectYoutubeChannels(state),
pendingChannels,

View file

@ -14,7 +14,6 @@ import HelpLink from 'component/common/help-link';
import { useHistory } from 'react-router';
type Props = {
channels: Array<ChannelClaim>,
channelUrls: Array<string>,
fetchChannelListMine: () => void,
fetchingChannels: boolean,

View file

@ -1,11 +1,11 @@
import { connect } from 'react-redux';
import { selectMyChannelClaims, selectFetchingMyChannels } from 'redux/selectors/claims';
import { selectHasChannels, selectFetchingMyChannels } from 'redux/selectors/claims';
import { selectActiveChannelClaim } from 'redux/selectors/app';
import { doSetActiveChannel } from 'redux/actions/app';
import CreatorDashboardPage from './view';
const select = (state) => ({
channels: selectMyChannelClaims(state),
hasChannels: selectHasChannels(state),
fetchingChannels: selectFetchingMyChannels(state),
activeChannelClaim: selectActiveChannelClaim(state),
});

View file

@ -9,14 +9,13 @@ import ChannelSelector from 'component/channelSelector';
import Yrbl from 'component/yrbl';
type Props = {
channels: Array<ChannelClaim>,
hasChannels: boolean,
fetchingChannels: boolean,
activeChannelClaim: ?ChannelClaim,
};
export default function CreatorDashboardPage(props: Props) {
const { channels, fetchingChannels, activeChannelClaim } = props;
const hasChannels = channels && channels.length > 0;
const { hasChannels, fetchingChannels, activeChannelClaim } = props;
return (
<Page>

View file

@ -12,7 +12,7 @@ import {
selectModeratorTimeoutMap,
selectPersonalTimeoutMap,
} from 'redux/selectors/comments';
import { selectMyChannelClaims } from 'redux/selectors/claims';
import { selectMyChannelClaimIds } from 'redux/selectors/claims';
import ListBlocked from './view';
const select = (state) => ({
@ -25,7 +25,7 @@ const select = (state) => ({
moderatorTimeoutMap: selectModeratorTimeoutMap(state),
moderatorBlockListDelegatorsMap: selectModeratorBlockListDelegatorsMap(state),
delegatorsById: selectModerationDelegatorsById(state),
myChannelClaims: selectMyChannelClaims(state),
myChannelClaimIds: selectMyChannelClaimIds(state),
fetchingModerationBlockList: selectFetchingModerationBlockList(state),
});

View file

@ -34,7 +34,7 @@ type Props = {
fetchModBlockedList: () => void,
fetchModAmIList: () => void,
delegatorsById: { [string]: { global: boolean, delegators: { name: string, claimId: string } } },
myChannelClaims: ?Array<ChannelClaim>,
myChannelClaimIds: ?Array<string>,
};
function ListBlocked(props: Props) {
@ -51,7 +51,7 @@ function ListBlocked(props: Props) {
fetchModBlockedList,
fetchModAmIList,
delegatorsById,
myChannelClaims,
myChannelClaimIds,
} = props;
const [viewMode, setViewMode] = usePersistedState('blocked-muted:display', VIEW.BLOCKED);
@ -60,14 +60,11 @@ function ListBlocked(props: Props) {
const stringifiedDelegatorsMap = JSON.stringify(delegatorsMap);
const stringifiedLocalDelegatorsMap = JSON.stringify(localDelegatorsMap);
const isAdmin =
myChannelClaims && myChannelClaims.some((c) => delegatorsById[c.claim_id] && delegatorsById[c.claim_id].global);
const isAdmin = myChannelClaimIds && myChannelClaimIds.some((id) => delegatorsById[id] && delegatorsById[id].global);
const isModerator =
myChannelClaims &&
myChannelClaims.some(
(c) => delegatorsById[c.claim_id] && Object.keys(delegatorsById[c.claim_id].delegators).length > 0
);
myChannelClaimIds &&
myChannelClaimIds.some((id) => delegatorsById[id] && Object.keys(delegatorsById[id].delegators).length > 0);
// **************************************************************************
@ -221,7 +218,7 @@ function ListBlocked(props: Props) {
function getRefreshElem() {
return (
myChannelClaims && (
myChannelClaimIds && (
<Button
icon={ICONS.REFRESH}
button="alt"

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux';
import { selectMyChannelClaims, selectFetchingMyChannels } from 'redux/selectors/claims';
import { selectHasChannels, selectFetchingMyChannels } from 'redux/selectors/claims';
import { doClearPublish } from 'redux/actions/publish';
import { selectActiveChannelClaim } from 'redux/selectors/app';
import { doFetchNoSourceClaims } from 'redux/actions/livestream';
@ -17,7 +17,7 @@ const select = (state) => {
return {
channelName,
channelId,
channels: selectMyChannelClaims(state),
hasChannels: selectHasChannels(state),
fetchingChannels: selectFetchingMyChannels(state),
activeChannelClaim,
myLivestreamClaims: makeSelectLivestreamsForChannelId(channelId)(state),

View file

@ -19,7 +19,7 @@ import usePersistedState from 'effects/use-persisted-state';
import { LIVESTREAM_RTMP_URL } from 'constants/livestream';
type Props = {
channels: Array<ChannelClaim>,
hasChannels: boolean,
fetchingChannels: boolean,
activeChannelClaim: ?ChannelClaim,
pendingClaims: Array<Claim>,
@ -34,7 +34,7 @@ type Props = {
export default function LivestreamSetupPage(props: Props) {
const LIVESTREAM_CLAIM_POLL_IN_MS = 60000;
const {
channels,
hasChannels,
fetchingChannels,
activeChannelClaim,
pendingClaims,
@ -49,7 +49,6 @@ export default function LivestreamSetupPage(props: Props) {
const [sigData, setSigData] = React.useState({ signature: undefined, signing_ts: undefined });
const [showHelp, setShowHelp] = usePersistedState('livestream-help-seen', true);
const hasChannels = channels && channels.length > 0;
const hasLivestreamClaims = Boolean(myLivestreamClaims.length || pendingClaims.length);
function createStreamKey() {

View file

@ -402,6 +402,8 @@ export const selectMyClaimsOutpoints = createSelector(selectMyClaims, (myClaims)
export const selectFetchingMyChannels = (state: State) => selectState(state).fetchingMyChannels;
export const selectFetchingMyCollections = (state: State) => selectState(state).fetchingMyCollections;
export const selectMyChannelClaimIds = (state: State) => selectState(state).myChannelClaims;
export const selectMyChannelClaims = createSelector(selectState, selectClaimsById, (state, byId) => {
const ids = state.myChannelClaims;
if (!ids) {
@ -423,6 +425,11 @@ export const selectMyChannelUrls = createSelector(selectMyChannelClaims, (claims
claims ? claims.map((claim) => claim.canonical_url || claim.permanent_url) : undefined
);
export const selectHasChannels = (state: State) => {
const myChannelClaimIds = selectMyChannelClaimIds(state);
return myChannelClaimIds ? myChannelClaimIds.length > 0 : false;
};
export const selectMyCollectionIds = (state: State) => selectState(state).myCollectionClaims;
export const selectResolvingUris = createSelector(selectState, (state) => state.resolvingUris || []);