mirror of
https://github.com/cheeaun/phanpy.git
synced 2025-02-02 14:16:39 +01:00
Perf fixes
Turns out, adding an object to states.statuses proxyMap object, re-render ALL statuses
This commit is contained in:
parent
862107f2e6
commit
41df88e625
6 changed files with 71 additions and 73 deletions
43
src/app.jsx
43
src/app.jsx
|
@ -302,23 +302,23 @@ async function startStream() {
|
|||
});
|
||||
}
|
||||
|
||||
states.statuses.set(status.id, status);
|
||||
states.statuses[status.id] = status;
|
||||
if (status.reblog) {
|
||||
states.statuses.set(status.reblog.id, status.reblog);
|
||||
states.statuses[status.reblog.id] = status.reblog;
|
||||
}
|
||||
}, 5000);
|
||||
stream.on('update', handleNewStatus);
|
||||
stream.on('status.update', (status) => {
|
||||
console.log('STATUS.UPDATE', status);
|
||||
states.statuses.set(status.id, status);
|
||||
states.statuses[status.id] = status;
|
||||
if (status.reblog) {
|
||||
states.statuses.set(status.reblog.id, status.reblog);
|
||||
states.statuses[status.reblog.id] = status.reblog;
|
||||
}
|
||||
});
|
||||
stream.on('delete', (statusID) => {
|
||||
console.log('DELETE', statusID);
|
||||
// states.statuses.delete(statusID);
|
||||
const s = states.statuses.get(statusID);
|
||||
// delete states.statuses[statusID];
|
||||
const s = states.statuses[statusID];
|
||||
if (s) s._deleted = true;
|
||||
});
|
||||
stream.on('notification', (notification) => {
|
||||
|
@ -334,16 +334,14 @@ async function startStream() {
|
|||
states.notificationsNew.unshift(notification);
|
||||
}
|
||||
|
||||
if (notification.status && !states.statuses.has(notification.status.id)) {
|
||||
states.statuses.set(notification.status.id, notification.status);
|
||||
if (notification.status && !states.statuses[notification.status.id]) {
|
||||
states.statuses[notification.status.id] = notification.status;
|
||||
if (
|
||||
notification.status.reblog &&
|
||||
!states.statuses.has(notification.status.reblog.id)
|
||||
!states.statuses[notification.status.reblog.id]
|
||||
) {
|
||||
states.statuses.set(
|
||||
notification.status.reblog.id,
|
||||
notification.status.reblog,
|
||||
);
|
||||
states.statuses[notification.status.reblog.id] =
|
||||
notification.status.reblog;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -397,9 +395,9 @@ function startVisibility() {
|
|||
newStatuses[0].id !== states.home[0].id
|
||||
) {
|
||||
states.homeNew = newStatuses.map((status) => {
|
||||
states.statuses.set(status.id, status);
|
||||
states.statuses[status.id] = status;
|
||||
if (status.reblog) {
|
||||
states.statuses.set(status.reblog.id, status.reblog);
|
||||
states.statuses[status.reblog.id] = status.reblog;
|
||||
}
|
||||
return {
|
||||
id: status.id,
|
||||
|
@ -424,20 +422,15 @@ function startVisibility() {
|
|||
|
||||
if (
|
||||
notification.status &&
|
||||
!states.statuses.has(notification.status.id)
|
||||
!states.statuses[notification.status.id]
|
||||
) {
|
||||
states.statuses.set(
|
||||
notification.status.id,
|
||||
notification.status,
|
||||
);
|
||||
states.statuses[notification.status.id] = notification.status;
|
||||
if (
|
||||
notification.status.reblog &&
|
||||
!states.statuses.has(notification.status.reblog.id)
|
||||
!states.statuses[notification.status.reblog.id]
|
||||
) {
|
||||
states.statuses.set(
|
||||
notification.status.reblog.id,
|
||||
notification.status.reblog,
|
||||
);
|
||||
states.statuses[notification.status.reblog.id] =
|
||||
notification.status.reblog;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import './status.css';
|
|||
|
||||
import { getBlurHashAverageColor } from 'fast-blurhash';
|
||||
import mem from 'mem';
|
||||
import { memo } from 'preact/compat';
|
||||
import {
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
|
@ -61,7 +62,7 @@ function Status({
|
|||
|
||||
const snapStates = useSnapshot(states);
|
||||
if (!status) {
|
||||
status = snapStates.statuses.get(statusID);
|
||||
status = snapStates.statuses[statusID];
|
||||
}
|
||||
if (!status) {
|
||||
return null;
|
||||
|
@ -106,6 +107,8 @@ function Status({
|
|||
_deleted,
|
||||
} = status;
|
||||
|
||||
console.debug('RENDER Status', id, status?.account.displayName);
|
||||
|
||||
const createdAtDate = new Date(createdAt);
|
||||
const editedAtDate = new Date(editedAt);
|
||||
|
||||
|
@ -122,20 +125,20 @@ function Status({
|
|||
}
|
||||
const [inReplyToAccount, setInReplyToAccount] = useState(inReplyToAccountRef);
|
||||
if (!withinContext && !inReplyToAccount && inReplyToAccountId) {
|
||||
const account = states.accounts.get(inReplyToAccountId);
|
||||
const account = states.accounts[inReplyToAccountId];
|
||||
if (account) {
|
||||
setInReplyToAccount(account);
|
||||
} else {
|
||||
memFetchAccount(inReplyToAccountId)
|
||||
.then((account) => {
|
||||
setInReplyToAccount(account);
|
||||
states.accounts.set(account.id, account);
|
||||
states.accounts[account.id] = account;
|
||||
})
|
||||
.catch((e) => {});
|
||||
}
|
||||
}
|
||||
|
||||
const showSpoiler = snapStates.spoilers.has(id) || false;
|
||||
const showSpoiler = !!snapStates.spoilers[id] || false;
|
||||
|
||||
const debugHover = (e) => {
|
||||
if (e.shiftKey) {
|
||||
|
@ -321,9 +324,9 @@ function Status({
|
|||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (showSpoiler) {
|
||||
states.spoilers.delete(id);
|
||||
delete states.spoilers[id];
|
||||
} else {
|
||||
states.spoilers.set(id, true);
|
||||
states.spoilers[id] = true;
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
@ -388,7 +391,7 @@ function Status({
|
|||
poll={poll}
|
||||
readOnly={readOnly}
|
||||
onUpdate={(newPoll) => {
|
||||
states.statuses.get(id).poll = newPoll;
|
||||
states.statuses[id].poll = newPoll;
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
@ -400,9 +403,9 @@ function Status({
|
|||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (showSpoiler) {
|
||||
states.spoilers.delete(id);
|
||||
delete states.spoilers[id];
|
||||
} else {
|
||||
states.spoilers.set(id, true);
|
||||
states.spoilers[id] = true;
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
@ -519,28 +522,26 @@ function Status({
|
|||
}
|
||||
}
|
||||
// Optimistic
|
||||
states.statuses.set(id, {
|
||||
states.statuses[id] = {
|
||||
...status,
|
||||
reblogged: !reblogged,
|
||||
reblogsCount: reblogsCount + (reblogged ? -1 : 1),
|
||||
});
|
||||
};
|
||||
if (reblogged) {
|
||||
const newStatus = await masto.v1.statuses.unreblog(
|
||||
id,
|
||||
);
|
||||
states.statuses.set(newStatus.id, newStatus);
|
||||
states.statuses[newStatus.id] = newStatus;
|
||||
} else {
|
||||
const newStatus = await masto.v1.statuses.reblog(id);
|
||||
states.statuses.set(newStatus.id, newStatus);
|
||||
states.statuses.set(
|
||||
newStatus.reblog.id,
|
||||
newStatus.reblog,
|
||||
);
|
||||
states.statuses[newStatus.id] = newStatus;
|
||||
states.statuses[newStatus.reblog.id] =
|
||||
newStatus.reblog;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
// Revert optimistism
|
||||
states.statuses.set(id, status);
|
||||
states.statuses[id] = status;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
@ -557,25 +558,25 @@ function Status({
|
|||
onClick={async () => {
|
||||
try {
|
||||
// Optimistic
|
||||
states.statuses.set(statusID, {
|
||||
states.statuses[statusID] = {
|
||||
...status,
|
||||
favourited: !favourited,
|
||||
favouritesCount:
|
||||
favouritesCount + (favourited ? -1 : 1),
|
||||
});
|
||||
};
|
||||
if (favourited) {
|
||||
const newStatus = await masto.v1.statuses.unfavourite(
|
||||
id,
|
||||
);
|
||||
states.statuses.set(newStatus.id, newStatus);
|
||||
states.statuses[newStatus.id] = newStatus;
|
||||
} else {
|
||||
const newStatus = await masto.v1.statuses.favourite(id);
|
||||
states.statuses.set(newStatus.id, newStatus);
|
||||
states.statuses[newStatus.id] = newStatus;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
// Revert optimistism
|
||||
states.statuses.set(statusID, status);
|
||||
states.statuses[statusID] = status;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
@ -590,23 +591,23 @@ function Status({
|
|||
onClick={async () => {
|
||||
try {
|
||||
// Optimistic
|
||||
states.statuses.set(statusID, {
|
||||
states.statuses[statusID] = {
|
||||
...status,
|
||||
bookmarked: !bookmarked,
|
||||
});
|
||||
};
|
||||
if (bookmarked) {
|
||||
const newStatus = await masto.v1.statuses.unbookmark(
|
||||
id,
|
||||
);
|
||||
states.statuses.set(newStatus.id, newStatus);
|
||||
states.statuses[newStatus.id] = newStatus;
|
||||
} else {
|
||||
const newStatus = await masto.v1.statuses.bookmark(id);
|
||||
states.statuses.set(newStatus.id, newStatus);
|
||||
states.statuses[newStatus.id] = newStatus;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
// Revert optimistism
|
||||
states.statuses.set(statusID, status);
|
||||
states.statuses[statusID] = status;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
@ -1437,4 +1438,4 @@ function formatDuration(time) {
|
|||
}
|
||||
}
|
||||
|
||||
export default Status;
|
||||
export default memo(Status);
|
||||
|
|
|
@ -18,6 +18,8 @@ function Home({ hidden }) {
|
|||
const [uiState, setUIState] = useState('default');
|
||||
const [showMore, setShowMore] = useState(false);
|
||||
|
||||
console.debug('RENDER Home');
|
||||
|
||||
const homeIterator = useRef(
|
||||
masto.v1.timelines.listHome({
|
||||
limit: LIMIT,
|
||||
|
@ -36,9 +38,9 @@ function Home({ hidden }) {
|
|||
return { done: true };
|
||||
}
|
||||
const homeValues = allStatuses.value.map((status) => {
|
||||
states.statuses.set(status.id, status);
|
||||
states.statuses[status.id] = status;
|
||||
if (status.reblog) {
|
||||
states.statuses.set(status.reblog.id, status.reblog);
|
||||
states.statuses[status.reblog.id] = status.reblog;
|
||||
}
|
||||
return {
|
||||
id: status.id,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import './notifications.css';
|
||||
|
||||
import { Link } from 'preact-router/match';
|
||||
import { memo } from 'preact/compat';
|
||||
import { useEffect, useRef, useState } from 'preact/hooks';
|
||||
import { useSnapshot } from 'valtio';
|
||||
|
||||
|
@ -205,6 +206,8 @@ function Notifications() {
|
|||
const [showMore, setShowMore] = useState(false);
|
||||
const [onlyMentions, setOnlyMentions] = useState(false);
|
||||
|
||||
console.debug('RENDER Notifications');
|
||||
|
||||
const notificationsIterator = useRef(
|
||||
masto.v1.notifications.list({
|
||||
limit: LIMIT,
|
||||
|
@ -224,7 +227,7 @@ function Notifications() {
|
|||
}
|
||||
const notificationsValues = allNotifications.value.map((notification) => {
|
||||
if (notification.status) {
|
||||
states.statuses.set(notification.status.id, notification.status);
|
||||
states.statuses[notification.status.id] = notification.status;
|
||||
}
|
||||
return notification;
|
||||
});
|
||||
|
@ -411,4 +414,4 @@ function Notifications() {
|
|||
);
|
||||
}
|
||||
|
||||
export default Notifications;
|
||||
export default memo(Notifications);
|
||||
|
|
|
@ -44,7 +44,7 @@ function StatusPage({ id }) {
|
|||
// console.log('onScroll');
|
||||
if (!scrollableRef.current) return;
|
||||
const { scrollTop } = scrollableRef.current;
|
||||
states.scrollPositions.set(id, scrollTop);
|
||||
states.scrollPositions[id] = scrollTop;
|
||||
}, 100);
|
||||
scrollableRef.current.addEventListener('scroll', onScroll, {
|
||||
passive: true,
|
||||
|
@ -63,7 +63,7 @@ function StatusPage({ id }) {
|
|||
if (cachedStatuses) {
|
||||
// Case 1: It's cached, let's restore them to make it snappy
|
||||
const reallyCachedStatuses = cachedStatuses.filter(
|
||||
(s) => states.statuses.has(s.id),
|
||||
(s) => states.statuses[s.id],
|
||||
// Some are not cached in the global state, so we need to filter them out
|
||||
);
|
||||
setStatuses(reallyCachedStatuses);
|
||||
|
@ -83,15 +83,15 @@ function StatusPage({ id }) {
|
|||
const heroFetch = () => masto.v1.statuses.fetch(id);
|
||||
const contextFetch = masto.v1.statuses.fetchContext(id);
|
||||
|
||||
const hasStatus = snapStates.statuses.has(id);
|
||||
let heroStatus = snapStates.statuses.get(id);
|
||||
const hasStatus = !!snapStates.statuses[id];
|
||||
let heroStatus = snapStates.statuses[id];
|
||||
if (hasStatus) {
|
||||
console.log('Hero status is cached');
|
||||
// NOTE: This might conflict if the user interacts with the status before the fetch is done, e.g. favouriting it
|
||||
// heroTimer = setTimeout(async () => {
|
||||
// try {
|
||||
// heroStatus = await heroFetch();
|
||||
// states.statuses.set(id, heroStatus);
|
||||
// states.statuses[id] = heroStatus;
|
||||
// } catch (e) {
|
||||
// // Silent fail if status is cached
|
||||
// console.error(e);
|
||||
|
@ -100,7 +100,7 @@ function StatusPage({ id }) {
|
|||
} else {
|
||||
try {
|
||||
heroStatus = await heroFetch();
|
||||
states.statuses.set(id, heroStatus);
|
||||
states.statuses[id] = heroStatus;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
setUIState('error');
|
||||
|
@ -113,11 +113,11 @@ function StatusPage({ id }) {
|
|||
const { ancestors, descendants } = context;
|
||||
|
||||
ancestors.forEach((status) => {
|
||||
states.statuses.set(status.id, status);
|
||||
states.statuses[status.id] = status;
|
||||
});
|
||||
const nestedDescendants = [];
|
||||
descendants.forEach((status) => {
|
||||
states.statuses.set(status.id, status);
|
||||
states.statuses[status.id] = status;
|
||||
if (status.inReplyToAccountId === status.account.id) {
|
||||
// If replying to self, it's part of the thread, level 1
|
||||
nestedDescendants.push(status);
|
||||
|
@ -225,7 +225,7 @@ function StatusPage({ id }) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
const scrollPosition = states.scrollPositions.get(id);
|
||||
const scrollPosition = states.scrollPositions[id];
|
||||
if (scrollPosition && scrollableRef.current) {
|
||||
// Case 3: Not user initiated (e.g. back/forward button), restore to saved scroll position
|
||||
console.log('Case 3');
|
||||
|
@ -247,7 +247,7 @@ function StatusPage({ id }) {
|
|||
}
|
||||
}, [statuses, uiState]);
|
||||
|
||||
const heroStatus = snapStates.statuses.get(id);
|
||||
const heroStatus = snapStates.statuses[id];
|
||||
const heroDisplayName = useMemo(() => {
|
||||
// Remove shortcodes from display name
|
||||
if (!heroStatus) return '';
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
import { proxy } from 'valtio';
|
||||
import { proxyMap } from 'valtio/utils';
|
||||
|
||||
export default proxy({
|
||||
history: [],
|
||||
statuses: proxyMap([]),
|
||||
statuses: {},
|
||||
home: [],
|
||||
homeNew: [],
|
||||
homeLastFetchTime: null,
|
||||
notifications: [],
|
||||
notificationsNew: [],
|
||||
notificationsLastFetchTime: null,
|
||||
accounts: new Map(),
|
||||
accounts: {},
|
||||
reloadStatusPage: 0,
|
||||
spoilers: proxyMap([]),
|
||||
scrollPositions: new Map(),
|
||||
spoilers: {},
|
||||
scrollPositions: {},
|
||||
// Modals
|
||||
showCompose: false,
|
||||
showSettings: false,
|
||||
|
|
Loading…
Reference in a new issue