mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
perf(feed): optimize posts rendering via props refactoring, memoizations
This commit is contained in:
@@ -115,10 +115,11 @@ const CatalogPost = ({ post }: { post: Comment }) => {
|
||||
subplebbitAddress,
|
||||
timestamp,
|
||||
title,
|
||||
thumbnailUrl,
|
||||
} = post || {};
|
||||
const linkCount = useCountLinksInReplies(post);
|
||||
|
||||
const commentMediaInfo = useCommentMediaInfo(post);
|
||||
const commentMediaInfo = useCommentMediaInfo(link, thumbnailUrl, linkWidth, linkHeight);
|
||||
const hasThumbnail = getHasThumbnail(commentMediaInfo, link);
|
||||
|
||||
const { hidden } = useHide({ cid });
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Comment } from '@plebbit/plebbit-react-hooks';
|
||||
import { CommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail, getMediaDimensions } from '../../lib/utils/media-utils';
|
||||
import { getHostname } from '../../lib/utils/url-utils';
|
||||
import useExpandedMediaStore from '../../stores/use-expanded-media-store';
|
||||
@@ -14,12 +13,14 @@ interface MediaProps {
|
||||
deleted?: boolean;
|
||||
displayHeight?: string;
|
||||
displayWidth?: string;
|
||||
isDescription?: boolean;
|
||||
isRules?: boolean;
|
||||
isFloatingEmbed?: boolean;
|
||||
isOutOfFeed?: boolean;
|
||||
isReply?: boolean;
|
||||
linkHeight?: number;
|
||||
linkWidth?: number;
|
||||
post?: Comment;
|
||||
parentCid?: string;
|
||||
removed?: boolean;
|
||||
spoiler?: boolean;
|
||||
showThumbnail?: boolean;
|
||||
@@ -130,12 +131,12 @@ interface ImageProps {
|
||||
displayHeight: string;
|
||||
displayWidth: string;
|
||||
isOutOfFeed: boolean;
|
||||
post: Comment | undefined;
|
||||
parentCid?: string;
|
||||
spoiler?: boolean;
|
||||
}
|
||||
|
||||
const Image = ({ commentMediaInfo, displayHeight, displayWidth, isOutOfFeed, post }: ImageProps) => {
|
||||
const Image = ({ commentMediaInfo, displayHeight, displayWidth, isOutOfFeed, parentCid, spoiler }: ImageProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { parentCid, spoiler } = post || {};
|
||||
const { type, url } = commentMediaInfo || {};
|
||||
const isReply = parentCid;
|
||||
const isMobile = useIsMobile();
|
||||
@@ -181,7 +182,7 @@ const Image = ({ commentMediaInfo, displayHeight, displayWidth, isOutOfFeed, pos
|
||||
{mediaDimensions && `, ${mediaDimensions}`})
|
||||
</div>
|
||||
)}
|
||||
{type && !isImageExpanded && <div className={styles.fileInfo}>{`${post?.spoiler ? `${t('spoiler')} - ` : ''} ${getDisplayMediaInfoType(type, t)}`}</div>}
|
||||
{type && !isImageExpanded && <div className={styles.fileInfo}>{`${spoiler ? `${t('spoiler')} - ` : ''} ${getDisplayMediaInfoType(type, t)}`}</div>}
|
||||
</span>
|
||||
) : (
|
||||
<span
|
||||
@@ -197,8 +198,20 @@ const Image = ({ commentMediaInfo, displayHeight, displayWidth, isOutOfFeed, pos
|
||||
);
|
||||
};
|
||||
|
||||
const CommentMedia = ({ commentMediaInfo, isFloatingEmbed, post, showThumbnail, setShowThumbnail }: MediaProps) => {
|
||||
const { deleted, linkHeight, linkWidth, parentCid, removed, spoiler } = post || {};
|
||||
const CommentMedia = ({
|
||||
commentMediaInfo,
|
||||
deleted,
|
||||
isDescription,
|
||||
isFloatingEmbed,
|
||||
isRules,
|
||||
linkHeight,
|
||||
linkWidth,
|
||||
parentCid,
|
||||
removed,
|
||||
showThumbnail,
|
||||
setShowThumbnail,
|
||||
spoiler,
|
||||
}: MediaProps) => {
|
||||
const isReply = parentCid;
|
||||
const { t } = useTranslation();
|
||||
const isMobile = useIsMobile();
|
||||
@@ -235,14 +248,20 @@ const CommentMedia = ({ commentMediaInfo, isFloatingEmbed, post, showThumbnail,
|
||||
displayWidth = '100%';
|
||||
displayHeight = '100%';
|
||||
}
|
||||
const { isDescription, isRules } = post || {}; // custom properties, not from api
|
||||
const isOutOfFeed = isDescription || isRules || isFloatingEmbed || spoiler; // virtuoso wrapper unneeded
|
||||
const isOutOfFeed = isDescription || isRules || isFloatingEmbed || spoiler || false; // virtuoso wrapper unneeded
|
||||
|
||||
return (
|
||||
<span className={styles.content}>
|
||||
{commentMediaInfo?.type === 'image' ? (
|
||||
// images just enlarge when clicked, so they don't need two separate components
|
||||
<Image commentMediaInfo={commentMediaInfo} displayHeight={displayHeight} displayWidth={displayWidth} isOutOfFeed={isOutOfFeed} post={post} />
|
||||
<Image
|
||||
commentMediaInfo={commentMediaInfo}
|
||||
displayHeight={displayHeight}
|
||||
displayWidth={displayWidth}
|
||||
isOutOfFeed={isOutOfFeed}
|
||||
parentCid={parentCid}
|
||||
spoiler={spoiler}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<span className={`${showThumbnail ? styles.show : styles.hide} ${styles.thumbnail}`}>
|
||||
@@ -259,9 +278,9 @@ const CommentMedia = ({ commentMediaInfo, isFloatingEmbed, post, showThumbnail,
|
||||
setShowThumbnail={setShowThumbnail}
|
||||
/>
|
||||
)}
|
||||
{isMobile && type && <div className={styles.fileInfo}>{`${post?.spoiler ? `${t('spoiler')} - ` : ''} ${getDisplayMediaInfoType(type, t)}`}</div>}
|
||||
{isMobile && type && <div className={styles.fileInfo}>{`${spoiler ? `${t('spoiler')} - ` : ''} ${getDisplayMediaInfoType(type, t)}`}</div>}
|
||||
</span>
|
||||
{!showThumbnail && <Media commentMediaInfo={commentMediaInfo} isReply={post?.parentCid} setShowThumbnail={setShowThumbnail} />}
|
||||
{!showThumbnail && <Media commentMediaInfo={commentMediaInfo} isReply={!!parentCid} setShowThumbnail={setShowThumbnail} />}
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Link, useLocation, useParams } from 'react-router-dom';
|
||||
import { Comment, useAuthorAvatar, useEditedComment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
||||
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
||||
import styles from '../../views/post/post.module.css';
|
||||
import { getDisplayMediaInfoType, getHasThumbnail, getMediaDimensions } from '../../lib/utils/media-utils';
|
||||
import { CommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail, getMediaDimensions } from '../../lib/utils/media-utils';
|
||||
import { hashStringToColor, getTextColorForBackground } from '../../lib/utils/post-utils';
|
||||
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||
import { isValidURL } from '../../lib/utils/url-utils';
|
||||
@@ -222,17 +222,21 @@ const PostInfo = ({ openReplyModal, post, postReplyCount = 0, roles, isHidden }:
|
||||
);
|
||||
};
|
||||
|
||||
const PostMedia = ({ post, hasThumbnail }: PostProps) => {
|
||||
interface PostMediaProps {
|
||||
commentMediaInfo: CommentMediaInfo | undefined;
|
||||
hasThumbnail: boolean;
|
||||
isDescription: boolean;
|
||||
isRules: boolean;
|
||||
spoiler: boolean;
|
||||
deleted: boolean;
|
||||
removed: boolean;
|
||||
linkHeight: number;
|
||||
linkWidth: number;
|
||||
parentCid: string;
|
||||
}
|
||||
|
||||
const PostMedia = ({ commentMediaInfo, hasThumbnail, isDescription, isRules, spoiler, deleted, removed, linkHeight, linkWidth, parentCid }: PostMediaProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { spoiler, cid } = post || {};
|
||||
|
||||
// Reset state by remounting component when post changes
|
||||
return <PostMediaContent key={cid} post={post} hasThumbnail={hasThumbnail} spoiler={spoiler} t={t} />;
|
||||
};
|
||||
|
||||
const PostMediaContent = ({ post, hasThumbnail, spoiler, t }: { post: any; hasThumbnail: boolean | undefined; spoiler: boolean; t: any }) => {
|
||||
const { isDescription, isRules } = post || {}; // custom properties, not from api
|
||||
const commentMediaInfo = useCommentMediaInfo(post);
|
||||
const { url } = commentMediaInfo || {};
|
||||
let type = commentMediaInfo?.type;
|
||||
const gifFrameUrl = useFetchGifFirstFrame(url);
|
||||
@@ -247,7 +251,7 @@ const PostMediaContent = ({ post, hasThumbnail, spoiler, t }: { post: any; hasTh
|
||||
const [showThumbnail, setShowThumbnail] = useState(true);
|
||||
|
||||
const mediaDimensions = getMediaDimensions(commentMediaInfo);
|
||||
|
||||
console.log('mediaDimensions', mediaDimensions);
|
||||
return (
|
||||
<div className={styles.file}>
|
||||
<div className={styles.fileText}>
|
||||
@@ -268,8 +272,7 @@ const PostMediaContent = ({ post, hasThumbnail, spoiler, t }: { post: any; hasTh
|
||||
)}
|
||||
{showThumbnail && !hasThumbnail && embedUrl && canEmbed(embedUrl) && (
|
||||
<span>
|
||||
{' '}
|
||||
[
|
||||
-[
|
||||
<span className={styles.closeMedia} onClick={() => setShowThumbnail(false)}>
|
||||
{t('open')}
|
||||
</span>
|
||||
@@ -281,10 +284,17 @@ const PostMediaContent = ({ post, hasThumbnail, spoiler, t }: { post: any; hasTh
|
||||
<div className={styles.fileThumbnail}>
|
||||
<CommentMedia
|
||||
commentMediaInfo={commentMediaInfo}
|
||||
post={post}
|
||||
deleted={deleted}
|
||||
isDescription={isDescription}
|
||||
isRules={isRules}
|
||||
removed={removed}
|
||||
linkHeight={linkHeight}
|
||||
linkWidth={linkWidth}
|
||||
showThumbnail={showThumbnail}
|
||||
setShowThumbnail={setShowThumbnail}
|
||||
isOutOfFeed={isDescription || isRules}
|
||||
parentCid={parentCid}
|
||||
spoiler={spoiler}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -300,11 +310,13 @@ const Reply = ({ openReplyModal, postReplyCount, reply, roles }: PostProps) => {
|
||||
post = editedComment;
|
||||
}
|
||||
|
||||
const { author, cid, deleted, link, postCid, reason, removed, subplebbitAddress } = post || {};
|
||||
const { author, cid, deleted, link, linkHeight, linkWidth, postCid, reason, removed, spoiler, subplebbitAddress, thumbnailUrl, parentCid } = post || {};
|
||||
const { isDescription, isRules } = post || {}; // custom properties, not from api
|
||||
|
||||
const isRouteLinkToReply = useLocation().pathname.startsWith(`/p/${subplebbitAddress}/c/${cid}`);
|
||||
const { hidden } = useHide({ cid });
|
||||
|
||||
const commentMediaInfo = useCommentMediaInfo(post);
|
||||
const commentMediaInfo = useCommentMediaInfo(link, thumbnailUrl, linkWidth, linkHeight);
|
||||
const hasThumbnail = getHasThumbnail(commentMediaInfo, link);
|
||||
|
||||
return (
|
||||
@@ -312,7 +324,20 @@ const Reply = ({ openReplyModal, postReplyCount, reply, roles }: PostProps) => {
|
||||
<div className={styles.sideArrows}>{'>>'}</div>
|
||||
<div className={`${styles.reply} ${isRouteLinkToReply && styles.highlight}`} data-cid={cid} data-author-address={author?.shortAddress} data-post-cid={postCid}>
|
||||
<PostInfo openReplyModal={openReplyModal} post={post} postReplyCount={postReplyCount} roles={roles} isHidden={hidden} />
|
||||
{link && !hidden && !(deleted || removed) && isValidURL(link) && <PostMedia post={post} hasThumbnail={hasThumbnail} />}
|
||||
{link && !hidden && !(deleted || removed) && isValidURL(link) && (
|
||||
<PostMedia
|
||||
commentMediaInfo={commentMediaInfo}
|
||||
hasThumbnail={hasThumbnail}
|
||||
isDescription={isDescription}
|
||||
isRules={isRules}
|
||||
spoiler={spoiler}
|
||||
deleted={deleted}
|
||||
removed={removed}
|
||||
linkHeight={linkHeight}
|
||||
linkWidth={linkWidth}
|
||||
parentCid={parentCid}
|
||||
/>
|
||||
)}
|
||||
{!hidden && (!(removed || deleted) || ((removed || deleted) && reason)) && <CommentContent comment={post} />}
|
||||
</div>
|
||||
</div>
|
||||
@@ -321,7 +346,7 @@ const Reply = ({ openReplyModal, postReplyCount, reply, roles }: PostProps) => {
|
||||
|
||||
const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies = true }: PostProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { author, cid, content, deleted, link, pinned, postCid, removed, state, subplebbitAddress } = post || {};
|
||||
const { author, cid, content, deleted, link, linkHeight, linkWidth, pinned, postCid, removed, spoiler, state, subplebbitAddress, thumbnailUrl, parentCid } = post || {};
|
||||
const { isDescription, isRules } = post || {}; // custom properties, not from api
|
||||
const params = useParams();
|
||||
const location = useLocation();
|
||||
@@ -353,7 +378,7 @@ const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies
|
||||
replyCount: 0,
|
||||
};
|
||||
|
||||
const commentMediaInfo = useCommentMediaInfo(post);
|
||||
const commentMediaInfo = useCommentMediaInfo(link, thumbnailUrl, linkWidth, linkHeight);
|
||||
const hasThumbnail = getHasThumbnail(commentMediaInfo, link);
|
||||
|
||||
return (
|
||||
@@ -373,7 +398,20 @@ const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies
|
||||
)}
|
||||
<div data-cid={cid} data-author-address={author?.shortAddress} data-post-cid={postCid} className={shouldShowSnow() && hasThumbnail ? styles.xmasHatWrapper : ''}>
|
||||
{shouldShowSnow() && hasThumbnail && <img src={`${process.env.PUBLIC_URL}/assets/xmashat.gif`} className={styles.xmasHat} alt='' />}
|
||||
{link && !isHidden && !(deleted || removed) && isValidURL(link) && <PostMedia post={post} hasThumbnail={hasThumbnail} />}
|
||||
{link && !isHidden && !(deleted || removed) && isValidURL(link) && (
|
||||
<PostMedia
|
||||
commentMediaInfo={commentMediaInfo}
|
||||
hasThumbnail={hasThumbnail}
|
||||
isDescription={isDescription}
|
||||
isRules={isRules}
|
||||
spoiler={spoiler}
|
||||
deleted={deleted}
|
||||
removed={removed}
|
||||
linkHeight={linkHeight}
|
||||
linkWidth={linkWidth}
|
||||
parentCid={parentCid}
|
||||
/>
|
||||
)}
|
||||
<PostInfo isHidden={hidden} openReplyModal={openReplyModal} post={post} postReplyCount={replyCount} roles={roles} />
|
||||
{!isHidden && !content && !(deleted || removed) && <div className={styles.spacer} />}
|
||||
{!isHidden && <CommentContent comment={post} />}
|
||||
|
||||
@@ -132,8 +132,8 @@ const BlockBoardButton = ({ address }: { address: string }) => {
|
||||
|
||||
const PostMenuDesktop = ({ post }: { post: Comment }) => {
|
||||
const { t } = useTranslation();
|
||||
const { author, cid, isDescription, isRules, link, postCid, subplebbitAddress } = post || {};
|
||||
const commentMediaInfo = getCommentMediaInfo(post);
|
||||
const { author, cid, isDescription, isRules, link, thumbnailUrl, linkWidth, linkHeight, postCid, subplebbitAddress } = post || {};
|
||||
const commentMediaInfo = getCommentMediaInfo(link, thumbnailUrl, linkWidth, linkHeight);
|
||||
const { thumbnail, type, url } = commentMediaInfo || {};
|
||||
const [menuBtnRotated, setMenuBtnRotated] = useState(false);
|
||||
|
||||
|
||||
@@ -122,9 +122,9 @@ const BlockBoardButton = ({ address }: { address: string }) => {
|
||||
};
|
||||
|
||||
const PostMenuMobile = ({ post }: { post: Comment }) => {
|
||||
const { author, cid, deleted, isDescription, isRules, link, parentCid, postCid, removed, subplebbitAddress } = post || {};
|
||||
const { author, cid, deleted, isDescription, isRules, link, linkHeight, linkWidth, parentCid, postCid, removed, subplebbitAddress, thumbnailUrl } = post || {};
|
||||
const { isAccountMod, isAccountCommentAuthor } = useEditCommentPrivileges({ commentAuthorAddress: author?.address, subplebbitAddress });
|
||||
const commentMediaInfo = getCommentMediaInfo(post);
|
||||
const commentMediaInfo = getCommentMediaInfo(link, thumbnailUrl, linkWidth, linkHeight);
|
||||
const { thumbnail, type, url } = commentMediaInfo || {};
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||
const { refs, floatingStyles, context } = useFloating({
|
||||
|
||||
@@ -27,7 +27,25 @@ import _ from 'lodash';
|
||||
|
||||
const PostInfoAndMedia = ({ openReplyModal, post, postReplyCount = 0, roles }: PostProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { author, cid, deleted, link, locked, parentCid, pinned, postCid, reason, removed, shortCid, state, subplebbitAddress, timestamp } = post || {};
|
||||
const {
|
||||
author,
|
||||
cid,
|
||||
deleted,
|
||||
link,
|
||||
linkHeight,
|
||||
linkWidth,
|
||||
locked,
|
||||
parentCid,
|
||||
pinned,
|
||||
postCid,
|
||||
reason,
|
||||
removed,
|
||||
shortCid,
|
||||
state,
|
||||
subplebbitAddress,
|
||||
timestamp,
|
||||
thumbnailUrl,
|
||||
} = post || {};
|
||||
const isReply = parentCid;
|
||||
const title = post?.title?.trim();
|
||||
const { isDescription, isRules } = post || {}; // custom properties, not from api
|
||||
@@ -43,7 +61,7 @@ const PostInfoAndMedia = ({ openReplyModal, post, postReplyCount = 0, roles }: P
|
||||
const isInPostPageView = isPostPageView(location.pathname, params);
|
||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, params);
|
||||
|
||||
const commentMediaInfo = useCommentMediaInfo(post);
|
||||
const commentMediaInfo = useCommentMediaInfo(link, thumbnailUrl, linkWidth, linkHeight);
|
||||
const hasThumbnail = getHasThumbnail(commentMediaInfo, link);
|
||||
|
||||
const stateString = useStateString(post);
|
||||
@@ -179,25 +197,33 @@ const PostInfoAndMedia = ({ openReplyModal, post, postReplyCount = 0, roles }: P
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
{(hasThumbnail || link) && !(deleted || removed) && <PostMediaContent key={cid} post={post} link={link} t={t} />}
|
||||
{(hasThumbnail || link) && !(deleted || removed) && <PostMediaContent key={cid} post={post} link={link} />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const PostMediaContent = ({ post, link, t }: { post: any; link: string; t: any }) => {
|
||||
const PostMediaContent = ({ post, link }: { post: any; link: string }) => {
|
||||
const [showThumbnail, setShowThumbnail] = useState(true);
|
||||
const { isDescription, isRules } = post || {}; // custom properties, not from api
|
||||
const commentMediaInfo = useCommentMediaInfo(post);
|
||||
const { thumbnailUrl, linkWidth, linkHeight, spoiler, deleted, removed, parentCid } = post || {};
|
||||
const commentMediaInfo = useCommentMediaInfo(link, thumbnailUrl, linkWidth, linkHeight);
|
||||
const hasThumbnail = getHasThumbnail(commentMediaInfo, link);
|
||||
|
||||
return (
|
||||
hasThumbnail && (
|
||||
<CommentMedia
|
||||
commentMediaInfo={commentMediaInfo}
|
||||
post={post}
|
||||
deleted={deleted}
|
||||
isDescription={isDescription}
|
||||
isRules={isRules}
|
||||
removed={removed}
|
||||
linkHeight={linkHeight}
|
||||
linkWidth={linkWidth}
|
||||
showThumbnail={showThumbnail}
|
||||
setShowThumbnail={setShowThumbnail}
|
||||
isOutOfFeed={isDescription || isRules}
|
||||
parentCid={parentCid}
|
||||
spoiler={spoiler}
|
||||
/>
|
||||
)
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user