improved virtual list rendering

This commit is contained in:
Roland Osborne 2022-04-19 21:54:04 -07:00
parent b365c42ac3
commit 1aec124e21
2 changed files with 14 additions and 21 deletions

View File

@ -11,10 +11,6 @@ export function Conversation() {
const { state, actions } = useConversation(); const { state, actions } = useConversation();
useEffect(() => {
console.log(state.topics);
}, [state]);
return ( return (
<ConversationWrapper> <ConversationWrapper>
<div class="header"> <div class="header">

View File

@ -12,7 +12,7 @@ export function VirtualList({ topics }) {
const [ viewHeight, setViewHeight ] = useState(DEFAULT_LIST_HEIGHT); const [ viewHeight, setViewHeight ] = useState(DEFAULT_LIST_HEIGHT);
const [ canvasHeight, setCanvasHeight ] = useState(DEFAULT_LIST_HEIGHT*3); const [ canvasHeight, setCanvasHeight ] = useState(DEFAULT_LIST_HEIGHT*3);
const [ items, setItems ] = useState([]); const [ items, setItems ] = useState(new Map());
const [ scroll, setScroll ] = useState('hidden'); const [ scroll, setScroll ] = useState('hidden');
let latch = useRef(true); let latch = useRef(true);
@ -21,16 +21,12 @@ export function VirtualList({ topics }) {
let anchorBottom = useRef(true); let anchorBottom = useRef(true);
let listRef = useRef(); let listRef = useRef();
const addItemTop = (item) => { const addItem = (id, item) => {
setItems((i) => { i.unshift(item); return [...i] }); setItems((m) => { m.set(id, item); return new Map(m); })
} }
const addItemBottom = (item) => { const updateItem = (id, item) => {
setItems((i) => { i.push(item); return [...i] }); setItems((m) => { m.set(id, item); return new Map(m); })
}
const updateItem = (idx, item) => {
setItems((i) => { i[idx] = item; return [...i] });
} }
useEffect(() => { useEffect(() => {
@ -86,24 +82,24 @@ export function VirtualList({ topics }) {
top: below.top - (DEFAULT_ITEM_HEIGHT + 2 * GUTTER), top: below.top - (DEFAULT_ITEM_HEIGHT + 2 * GUTTER),
height: DEFAULT_ITEM_HEIGHT, height: DEFAULT_ITEM_HEIGHT,
index: containers.current[0].index - 1, index: containers.current[0].index - 1,
id: topics[containers.current[0].index - 1].id,
} }
containers.current.unshift(container); containers.current.unshift(container);
console.log("ADD ITEM BEFORE", container); addItem(container.id, getItem(container))
addItemTop(getItem(container))
anchorBottom.current = true; anchorBottom.current = true;
} }
} }
if (view.overscan.bottom < OVERSCAN) { if (view.overscan.bottom < OVERSCAN) {
if (containers.current[containers.current.length - 1].index + 1 < topics.length) { if (containers.current[containers.current.length - 1].index + 1 < topics.length) {
console.log("ADD ITEM AFTER");
let above = containers.current[containers.current.length - 1]; let above = containers.current[containers.current.length - 1];
let container = { let container = {
top: above.top + above.height + 2 * GUTTER, top: above.top + above.height + 2 * GUTTER,
height: DEFAULT_ITEM_HEIGHT, height: DEFAULT_ITEM_HEIGHT,
index: containers.current[containers.current.length - 1].index + 1, index: containers.current[containers.current.length - 1].index + 1,
id: topics[containers.current[containers.current.length - 1].index + 1].id,
} }
containers.current.push(container); containers.current.push(container);
addItemBottom(getItem(container)) addItem(container.id, getItem(container))
anchorBottom.current = false; anchorBottom.current = false;
} }
} }
@ -119,7 +115,7 @@ console.log("ADD ITEM AFTER");
pos -= (containers.current[i].height + 2 * GUTTER); pos -= (containers.current[i].height + 2 * GUTTER);
if (containers.current[i].top != pos) { if (containers.current[i].top != pos) {
containers.current[i].top = pos; containers.current[i].top = pos;
updateItem(i, getItem(containers.current[i])); updateItem(containers.current[i].id, getItem(containers.current[i]));
} }
} }
@ -133,7 +129,7 @@ console.log("ADD ITEM AFTER");
for (let i = 1; i < containers.current.length; i++) { for (let i = 1; i < containers.current.length; i++) {
if (containers.current[i].top != pos) { if (containers.current[i].top != pos) {
containers.current[i].top = pos; containers.current[i].top = pos;
updateItem(i, getItem(containers.current[i])); updateItem(containers.current[i].id, getItem(containers.current[i]));
} }
pos += containers.current[i].height + 2 * GUTTER; pos += containers.current[i].height + 2 * GUTTER;
} }
@ -178,11 +174,12 @@ console.log("ADD ITEM AFTER");
top: pos - DEFAULT_ITEM_HEIGHT, top: pos - DEFAULT_ITEM_HEIGHT,
height: DEFAULT_ITEM_HEIGHT, height: DEFAULT_ITEM_HEIGHT,
index: topics.length - 1, index: topics.length - 1,
id: topics[topics.length - 1].id,
} }
anchorBottom.current = true; anchorBottom.current = true;
containers.current.push(container); containers.current.push(container);
addItemBottom(getItem(container)); addItem(container.id, getItem(container));
listRef.current.scrollTo({ top: container.top, left: 0, behavior: 'smooth' }); listRef.current.scrollTo({ top: container.top, left: 0, behavior: 'smooth' });
} }
@ -228,7 +225,7 @@ console.log("ADD ITEM AFTER");
<VirtualListWrapper onScroll={onScrollView} onWheel={onScrollWheel}> <VirtualListWrapper onScroll={onScrollView} onWheel={onScrollWheel}>
<div class="rollview" style={{ overflowY: scroll }} ref={listRef} onScroll={onScrollView}> <div class="rollview" style={{ overflowY: scroll }} ref={listRef} onScroll={onScrollView}>
<div class="roll" style={{ height: canvasHeight }}> <div class="roll" style={{ height: canvasHeight }}>
{ items } { items.values() }
</div> </div>
</div> </div>
</VirtualListWrapper> </VirtualListWrapper>