Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

omnibus: scroller perf, devex enhancements #1197

Merged
merged 12 commits into from
Nov 21, 2022
Prev Previous commit
Next Next commit
channels: refactor pre-fetching behavior
First, prioritize the most recently viewed channel; then batch fetch the remaining channels.

Also, consolidate recentChannel tracking into a hook.
  • Loading branch information
tomholford committed Nov 18, 2022
commit 46c157fddfd747252175ce9ffd744c99d78d4069
12 changes: 4 additions & 8 deletions ui/src/chat/ChatChannel.tsx
Original file line number Diff line number Diff line change
@@ -15,23 +15,19 @@ import {
useChannel,
} from '@/state/groups/groups';
import ChannelHeader from '@/channels/ChannelHeader';
import { createStorageKey } from '@/logic/utils';
import { useLocalStorage } from 'usehooks-ts';
import useRecentChannel from '@/logic/useRecentChannel';

function ChatChannel({ title }: ViewProps) {
const { chShip, chName } = useParams();
const chFlag = `${chShip}/${chName}`;
const nest = `chat/${chFlag}`;
const flag = useRouteGroup();
const [, setRecent] = useLocalStorage(
createStorageKey(`recent-chan:${flag}`),
''
);
const { setRecentChannel } = useRecentChannel(flag);

useEffect(() => {
useChatState.getState().initialize(chFlag);
setRecent(nest);
}, [chFlag, nest, setRecent]);
setRecentChannel(nest);
}, [chFlag, nest, setRecentChannel]);

const messages = useMessagesForChat(chFlag);
const perms = useChatPerms(chFlag);
3 changes: 2 additions & 1 deletion ui/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// eslint-disable-next-line import/prefer-default-export
export const MESSAGE_FETCH_PAGE_SIZE = 100;
export const MESSAGE_FETCH_PAGE_SIZE = 200;
export const FETCH_BATCH_SIZE = 3;
export const MAX_DISPLAYED_OPTIONS = 40;

export const AUTHORS = [
12 changes: 4 additions & 8 deletions ui/src/diary/DiaryChannel.tsx
Original file line number Diff line number Diff line change
@@ -21,9 +21,8 @@ import useDismissChannelNotifications from '@/logic/useDismissChannelNotificatio
import { DiaryDisplayMode } from '@/types/diary';
import DiaryGridView from '@/diary/DiaryList/DiaryGridView';
import { Link } from 'react-router-dom';
import { useLocalStorage } from 'usehooks-ts';
import * as Toast from '@radix-ui/react-toast';
import { createStorageKey } from '@/logic/utils';
import useRecentChannel from '@/logic/useRecentChannel';
import DiaryListItem from './DiaryList/DiaryListItem';
import useDiaryActions from './useDiaryActions';

@@ -36,10 +35,7 @@ function DiaryChannel() {
const letters = useNotesForDiary(chFlag);
const location = useLocation();
const navigate = useNavigate();
const [, setRecent] = useLocalStorage(
createStorageKey(`recent-chan:${flag}`),
''
);
const { setRecentChannel } = useRecentChannel(flag);
const newNote = new URLSearchParams(location.search).get('new');
const [showToast, setShowToast] = useState(false);
const { didCopy, onCopy } = useDiaryActions({
@@ -78,8 +74,8 @@ function DiaryChannel() {

useEffect(() => {
useDiaryState.getState().initialize(chFlag);
setRecent(nest);
}, [chFlag, nest, setRecent]);
setRecentChannel(nest);
}, [chFlag, nest, setRecentChannel]);

useEffect(() => {
let timeout: any;
11 changes: 4 additions & 7 deletions ui/src/groups/Groups.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useEffect } from 'react';
import { Outlet, useLocation, useMatch, useNavigate } from 'react-router';
import { Outlet, useMatch, useNavigate } from 'react-router';
import {
useGang,
useGroup,
@@ -11,9 +11,9 @@ import api from '@/api';
import { useChatState } from '@/state/chat';
import { useHeapState } from '@/state/heap/heap';
import { useDiaryState } from '@/state/diary';
import { createStorageKey, nestToFlag } from '@/logic/utils';
import { useLocalStorage } from 'usehooks-ts';
import { nestToFlag } from '@/logic/utils';
import { useIsMobile } from '@/logic/useMedia';
import useRecentChannel from '@/logic/useRecentChannel';

function Groups() {
const navigate = useNavigate();
@@ -26,10 +26,7 @@ function Groups() {
path: '/groups/:ship/:name',
end: true,
});
const [recentChannel] = useLocalStorage(
createStorageKey(`recent-chan:${flag}`),
''
);
const { recentChannel } = useRecentChannel(flag);

useEffect(() => {
if (initialized && !group && !gang) {
14 changes: 5 additions & 9 deletions ui/src/heap/HeapChannel.tsx
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ import _ from 'lodash';
import cn from 'classnames';
import { Outlet, useParams, useNavigate } from 'react-router';
import { Helmet } from 'react-helmet';
import { useLocalStorage } from 'usehooks-ts';
import bigInt from 'big-integer';
import { ViewProps } from '@/types/groups';
import Layout from '@/components/Layout/Layout';
import {
@@ -29,9 +29,8 @@ import {
import HeapBlock from '@/heap/HeapBlock';
import HeapRow from '@/heap/HeapRow';
import useDismissChannelNotifications from '@/logic/useDismissChannelNotifications';
import { createStorageKey } from '@/logic/utils';
import { GRID, HeapCurio, HeapDisplayMode, HeapSortMode } from '@/types/heap';
import bigInt from 'big-integer';
import useRecentChannel from '@/logic/useRecentChannel';
import NewCurioForm from './NewCurioForm';

function HeapChannel({ title }: ViewProps) {
@@ -41,10 +40,7 @@ function HeapChannel({ title }: ViewProps) {
const flag = useRouteGroup();
const channel = useChannel(flag, nest);
const group = useGroup(flag);
const [, setRecent] = useLocalStorage(
createStorageKey(`recent-chan:${flag}`),
''
);
const { setRecentChannel } = useRecentChannel(flag);

const navigate = useNavigate();
const displayMode = useHeapDisplayMode(chFlag);
@@ -90,8 +86,8 @@ function HeapChannel({ title }: ViewProps) {

useEffect(() => {
useHeapState.getState().initialize(chFlag);
setRecent(nest);
}, [chFlag, nest, setRecent]);
setRecentChannel(nest);
}, [chFlag, nest, setRecentChannel]);

useDismissChannelNotifications({
nest,
22 changes: 19 additions & 3 deletions ui/src/logic/usePrefetchChannels.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { useCallback, useEffect } from 'react';
import { chunk } from 'lodash';
import { useGroup } from '@/state/groups';
import { useChatState } from '@/state/chat';
import { asyncForEach } from '@/lib';
import { useHeapState } from '@/state/heap/heap';
import { useDiaryState } from '@/state/diary';
import { FETCH_BATCH_SIZE } from '@/constants';
import { nestToFlag } from './utils';
import useRecentChannel from './useRecentChannel';

/**
* On load, prefetches the messages for the group that the user is currently in.
@@ -14,6 +17,7 @@ import { nestToFlag } from './utils';
*/
export default function usePrefetchChannels(flag: string) {
const group = useGroup(flag);
const { recentChannel } = useRecentChannel(flag);
const { initialize: initializeChat } = useChatState.getState();
const { initialize: initializeDiary } = useDiaryState.getState();
const { initialize: initializeHeap } = useHeapState.getState();
@@ -23,7 +27,7 @@ export default function usePrefetchChannels(flag: string) {
const [chType, chFlag] = nestToFlag(channel);
switch (chType) {
case 'chat':
initializeChat(chFlag);
await initializeChat(chFlag);
break;
case 'diary':
initializeDiary(chFlag);
@@ -39,8 +43,20 @@ export default function usePrefetchChannels(flag: string) {
);

const fetchAll = useCallback(async () => {
await asyncForEach(Object.keys(group?.channels ?? {}), fetchChannel);
}, [fetchChannel, group]);
// first, prioritize the recent channel
if (recentChannel && recentChannel !== '') {
await fetchChannel(recentChannel);
}

// defer the rest, in batches
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

const channels = Object.keys(group?.channels ?? {}).filter(
(c) => c !== recentChannel
);
const batched = chunk(channels, FETCH_BATCH_SIZE);
batched.forEach(async (batch) => {
await asyncForEach(batch, fetchChannel);
});
}, [fetchChannel, group, recentChannel]);

useEffect(() => {
if (!group) {
15 changes: 15 additions & 0 deletions ui/src/logic/useRecentChannel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useLocalStorage } from 'usehooks-ts';
import { createStorageKey } from './utils';

/**
* Tracks which channel was most recently visited
* @param flag The group flag
*/
export default function useRecentChannel(flag: string) {
const [recentChannel, setRecentChannel] = useLocalStorage(
createStorageKey(`recent-chan:${flag}`),
''
);

return { recentChannel, setRecentChannel };
}
2 changes: 1 addition & 1 deletion ui/src/state/chat/chat.ts
Original file line number Diff line number Diff line change
@@ -598,7 +598,7 @@ export const useChatState = createState<ChatState>(
draft.chatSubs.push(whom);
});

await makeWritsStore(
makeWritsStore(
whom,
get,
`/chat/${whom}/writs`,
3 changes: 2 additions & 1 deletion ui/src/state/chat/writs.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { BigIntOrderedMap, decToUd, udToDec, unixToDa } from '@urbit/api';
import bigInt from 'big-integer';
import { MESSAGE_FETCH_PAGE_SIZE } from '@/constants';
import api from '../../api';
import {
ChatWrit,
@@ -112,7 +113,7 @@ export default function makeWritsStore(
});
return {
initialize: async () => {
const writs = await scry<ChatWrits>(`/newest/100`);
const writs = await scry<ChatWrits>(`/newest/${MESSAGE_FETCH_PAGE_SIZE}`);
const sta = get();
sta.batchSet((draft) => {
const pact: Pact = {
11 changes: 6 additions & 5 deletions ui/src/state/diary/notes.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import bigInt from 'big-integer';
import { BigIntOrderedMap, decToUd, udToDec } from '@urbit/api';
import { MESSAGE_FETCH_PAGE_SIZE } from '@/constants';
import {
NoteDiff,
NoteSeal,
DiaryNote,
DiaryNotes,
DiaryFlag,
DiaryDiff,
DiaryUpdate,
DiaryOutlines,
DiaryLetter,
DiaryQuip,
} from '@/types/diary';
import { BigIntOrderedMap, decToUd, udToDec } from '@urbit/api';
import bigInt from 'big-integer';
import api from '../../api';
import { DiaryState } from './type';

@@ -75,7 +74,9 @@ export default function makeNotesStore(

return {
initialize: async () => {
const notes = await scry<DiaryOutlines>(`/newest/100/outline`);
const notes = await scry<DiaryOutlines>(
`/newest/${MESSAGE_FETCH_PAGE_SIZE}/outline`
);
const sta = get();
sta.batchSet((draft) => {
let noteMap = new BigIntOrderedMap<DiaryLetter>();
9 changes: 6 additions & 3 deletions ui/src/state/heap/curios.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { BigIntOrderedMap, decToUd, udToDec } from '@urbit/api';
import bigInt from 'big-integer';
import { MESSAGE_FETCH_PAGE_SIZE } from '@/constants';
import {
CurioDiff,
CurioSeal,
HeapCurio,
HeapCurios,
HeapFlag,
} from '@/types/heap';
import { BigIntOrderedMap, decToUd, udToDec } from '@urbit/api';
import bigInt from 'big-integer';
import api from '../../api';
import { HeapState } from './type';

@@ -70,7 +71,9 @@ export default function makeCuriosStore(

return {
initialize: async () => {
const curios = await scry<HeapCurios>(`/newest/100`);
const curios = await scry<HeapCurios>(
`/newest/${MESSAGE_FETCH_PAGE_SIZE}`
);
const sta = get();
sta.batchSet((draft) => {
let curioMap = new BigIntOrderedMap<HeapCurio>();