opti: 1.adjust eventlistener;

This commit is contained in:
mitsuha
2022-08-24 01:54:10 +08:00
parent 85838c77a1
commit ab1fe668b4
2 changed files with 35 additions and 15 deletions
@@ -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<TocType[]>([]);
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();
@@ -13,16 +13,16 @@ export const BLOCK_TYPES = {
HEADING3: 'heading3',
};
/* store page/block unmount-listener */
export const listenerMap = new Map<string, () => 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<any[]> => {
/* 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?.();
}