From ab1fe668b4fb37fc3dac349c39e39d50d9f8f80a Mon Sep 17 00:00:00 2001 From: mitsuha Date: Wed, 24 Aug 2022 01:54:10 +0800 Subject: [PATCH] opti: 1.adjust eventlistener; --- .../workspace/docs/components/toc/TOC.tsx | 20 ++++++++++--- .../src/pages/workspace/docs/utils/toc.ts | 30 ++++++++++++------- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/apps/ligo-virgo/src/pages/workspace/docs/components/toc/TOC.tsx b/apps/ligo-virgo/src/pages/workspace/docs/components/toc/TOC.tsx index be567780f7..dd12469d90 100644 --- a/apps/ligo-virgo/src/pages/workspace/docs/components/toc/TOC.tsx +++ b/apps/ligo-virgo/src/pages/workspace/docs/components/toc/TOC.tsx @@ -14,6 +14,7 @@ import { destroyEventList, getContentByAsyncBlocks, getPageTOC, + listenerMap, type TocType, } from '../../utils/toc'; @@ -123,24 +124,35 @@ export const Toc = (props: Props) => { const { page_id } = useParams(); const [tocDataSource, setTocDataSource] = useState([]); const [activeBlockId, setActiveBlockId] = useState(''); - const [blockEventListeners, setBlockEventListeners] = useState([]); const updateTocDataSource = useCallback(async () => { - destroyEventList(blockEventListeners); + /* page listener: trigger update-notice when add new group */ + const pageAsyncBlock = (await editor.getBlockByIds([page_id]))?.[0]; + if (!listenerMap.has(pageAsyncBlock.id)) { + listenerMap.set( + pageAsyncBlock.id, + pageAsyncBlock.onUpdate(updateTocDataSource) + ); + } + /* block listener: trigger update-notice when change block content */ const { children = [] } = (await editor.queryByPageId(page_id))?.[0] || {}; const asyncBlocks = (await editor.getBlockByIds(children)) || []; - const { tocContents, eventListeners } = await getContentByAsyncBlocks( + const { tocContents } = await getContentByAsyncBlocks( asyncBlocks, updateTocDataSource ); + /* toc: flat content */ const tocDataSource = getPageTOC(asyncBlocks, tocContents); setTocDataSource(tocDataSource); - setBlockEventListeners(eventListeners); + + /* remove listener when unmount component */ + return destroyEventList; }, [editor, page_id]); + /* init toc and add page/block update-listener & unmount-listener */ useEffect(() => { (async () => { await updateTocDataSource(); diff --git a/apps/ligo-virgo/src/pages/workspace/docs/utils/toc.ts b/apps/ligo-virgo/src/pages/workspace/docs/utils/toc.ts index 2ef9a39032..b9a6e5dd56 100644 --- a/apps/ligo-virgo/src/pages/workspace/docs/utils/toc.ts +++ b/apps/ligo-virgo/src/pages/workspace/docs/utils/toc.ts @@ -13,16 +13,16 @@ export const BLOCK_TYPES = { HEADING3: 'heading3', }; +/* store page/block unmount-listener */ +export const listenerMap = new Map void>(); + /* ๐Ÿ˜ž๐Ÿ˜žsorry, I don't know how to define unlimited dimensions array */ const getContentByAsyncBlocks = async ( asyncBlocks: AsyncBlock[] = [], callback: () => void ): Promise<{ tocContents: any[]; - eventListeners: (() => void | undefined)[]; }> => { - const eventListeners = []; - const collect = async (asyncBlocks): Promise => { /* maybe should recast it to tail recursion */ return await Promise.all( @@ -33,11 +33,14 @@ const getContentByAsyncBlocks = async ( return collect(asyncBlocks); } - /* get update notice */ - const destroyHandler = asyncBlock.onUpdate(callback); + /* add only once event listener for every block */ + if (!listenerMap.has(asyncBlock.id)) { + /* get update notice */ + const destroyHandler = asyncBlock.onUpdate(callback); - /* collect destroy handlers */ - eventListeners.push(destroyHandler); + /* collect destroy handlers */ + listenerMap.set(asyncBlock.id, destroyHandler); + } const { id, type } = asyncBlock; if (Object.values(BLOCK_TYPES).includes(type)) { @@ -57,10 +60,14 @@ const getContentByAsyncBlocks = async ( return { tocContents: await collect(asyncBlocks), - eventListeners, }; }; +/** + * get flat toc + * @param asyncBlocks + * @param tocContents + */ const getPageTOC = (asyncBlocks: AsyncBlock[], tocContents): TocType[] => { return tocContents .reduce((tocGroupContent, tocContent, index) => { @@ -83,9 +90,10 @@ const getPageTOC = (asyncBlocks: AsyncBlock[], tocContents): TocType[] => { .filter(Boolean); }; -const destroyEventList = ( - eventListeners: (() => void | undefined)[] = [] -): boolean => { +/* destroy page/block update-listener */ +const destroyEventList = (): boolean => { + const eventListeners = listenerMap.values(); + for (const eventListener of eventListeners) { eventListener?.(); }