perf: prevent unnecessary re-renders from RPC client state changes

This commit is contained in:
plebeius
2026-01-14 15:05:45 +01:00
parent 91cd84819d
commit 3799dccd88
8 changed files with 168 additions and 26 deletions
+10 -3
View File
@@ -1,7 +1,8 @@
import { useEffect, useMemo, useRef, useState, useCallback } from 'react';
import { Link, useLocation, useNavigationType, useParams } from 'react-router-dom';
import { Trans, useTranslation } from 'react-i18next';
import { Comment, useAccount, useFeed, useSubplebbit, useBlock, useAccountComments } from '@plebbit/plebbit-react-hooks';
import { Comment, useAccount, useFeed, useBlock, useAccountComments } from '@plebbit/plebbit-react-hooks';
import { useSubplebbitField } from '../../hooks/use-stable-subplebbit';
import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso';
import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
import useCatalogFeedRows from '../../hooks/use-catalog-feed-rows';
@@ -479,8 +480,14 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
}
}, [reset, setResetFunction, isVisible]);
const subplebbit = useSubplebbit({ subplebbitAddress });
const { error, shortAddress, state, title } = subplebbit || {};
// Use stable field selectors to avoid re-renders from updatingState changes
const error = useSubplebbitField(subplebbitAddress, (sub) => sub?.error);
const shortAddress = useSubplebbitField(subplebbitAddress, (sub) => sub?.shortAddress);
const title = useSubplebbitField(subplebbitAddress, (sub) => sub?.title);
// Derive state from updatedAt field - if updatedAt exists, state is 'succeeded'
const updatedAt = useSubplebbitField(subplebbitAddress, (sub) => sub?.updatedAt);
const state = updatedAt ? 'succeeded' : 'fetching-ipns';
const { blocked, unblock } = useBlock({ address: subplebbitAddress });
const feedLength = feed.length;
+1 -3
View File
@@ -1,7 +1,6 @@
import { useEffect, useMemo, useRef, FormEvent } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { Trans, useTranslation } from 'react-i18next';
import { useSubplebbits } from '@plebbit/plebbit-react-hooks';
import styles from './home.module.css';
import { useDefaultSubplebbits, useDefaultSubplebbitAddresses } from '../../hooks/use-default-subplebbits';
import useSubplebbitsStats from '../../hooks/use-subplebbits-stats';
@@ -191,7 +190,6 @@ export const HomeLogo = () => {
const Home = () => {
const defaultSubplebbits = useDefaultSubplebbits();
const subplebbitAddresses = useDefaultSubplebbitAddresses();
const { subplebbits } = useSubplebbits({ subplebbitAddresses });
const { closeDirectoryModal } = useDirectoryModalStore();
useEffect(() => {
@@ -214,7 +212,7 @@ const Home = () => {
<SearchBar />
<InfoBox />
<BoardsList multisub={defaultSubplebbits} />
<PopularThreadsBox multisub={defaultSubplebbits} subplebbits={subplebbits} />
<PopularThreadsBox multisub={defaultSubplebbits} subplebbitAddresses={subplebbitAddresses} />
<Stats subplebbitAddresses={subplebbitAddresses} />
<Footer />
</div>
@@ -1,7 +1,8 @@
import { memo, useMemo } from 'react';
import { memo, useMemo, useEffect } from 'react';
import { Link } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { Comment, Subplebbit } from '@plebbit/plebbit-react-hooks';
import { Comment, Subplebbit, useAccount } from '@plebbit/plebbit-react-hooks';
import useSubplebbitsStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits';
import styles from '../home.module.css';
import usePopularPosts from '../../../hooks/use-popular-posts';
import usePopularThreadsOptionsStore from '../../../stores/use-popular-threads-options-store';
@@ -12,6 +13,7 @@ import BoxModal from '../box-modal';
import { MultisubSubplebbit, useDefaultSubplebbits } from '../../../hooks/use-default-subplebbits';
import { getBoardPath } from '../../../lib/utils/route-utils';
import { removeMarkdown } from '../../../lib/utils/post-utils';
import { useStableSubplebbits } from '../../../hooks/use-stable-subplebbit';
interface PopularThreadProps {
post: Comment;
@@ -67,10 +69,25 @@ const PopularThreadCard = memo(
},
);
const PopularThreadsBox = ({ multisub, subplebbits }: { multisub: MultisubSubplebbit[]; subplebbits: any }) => {
// Uses stable subplebbits hook to avoid re-renders from updatingState changes
const PopularThreadsBox = ({ multisub, subplebbitAddresses }: { multisub: MultisubSubplebbit[]; subplebbitAddresses: string[] }) => {
const { t } = useTranslation();
const { showWorksafeContentOnly, showNsfwContentOnly } = usePopularThreadsOptionsStore();
const account = useAccount();
const addSubplebbitToStore = useSubplebbitsStore((state) => state.addSubplebbitToStore);
// Trigger fetching subplebbits (same as useSubplebbits does internally)
useEffect(() => {
if (!account || !subplebbitAddresses) return;
for (const address of subplebbitAddresses) {
addSubplebbitToStore(address, account).catch(() => {});
}
}, [subplebbitAddresses?.toString(), account?.id]);
// Use stable hook that only re-renders when actual content changes
const subplebbits = useStableSubplebbits(subplebbitAddresses);
const getFilteredSubplebbits = () => {
if (showWorksafeContentOnly) {
return subplebbits.filter((sub: Subplebbit) => {
+1
View File
@@ -71,6 +71,7 @@ const PostPage = () => {
const subplebbit = useSubplebbit({ subplebbitAddress });
const { error: subplebbitError, shortAddress, title } = subplebbit || {};
const defaultSubplebbits = useDefaultSubplebbits();
// if the comment is a reply, return the post comment instead, then the reply will be highlighted in the thread