export function useTOC()

in docs-sdk/markdown-renderer/src/utils/useTOC.ts [6:64]


export function useTOC(enable = false, ctnRef: React.RefObject<HTMLDivElement>) {
  const [headings, setHeadings] = useState<ITocHeading[]>([]);

  const check = useCallback(
    debounce(() => {
      if (!ctnRef.current || !enable) return;
      const headingEls: HTMLElement[] = Array.from(
        ctnRef.current.querySelectorAll(".cc-doc-toc")
      );
      setHeadings(oldHeadings => {
        const newHeadings = headingEls.reduce<ITocHeading[]>((acc, el) => {
          const match = /h(\d)/i.exec(el.tagName || el.nodeName);
          if (match && el.textContent && el.id) {
            acc.push({
              depth: Number(match[1]),
              id: el.id,
              text: el.textContent
            });
          }
          return acc;
        }, []);
        // 避免无限重刷
        if (isequal(newHeadings, oldHeadings)) return oldHeadings;
        return newHeadings;
      });
    }, 100),
    [enable]
  );

  useEffect(() => {
    if (enable) check();
  });
  // 通过MutationObserver来监听子元素的变化,调用check
  // 可能会有性能问题,暂时用useEffect
  // useEffect(() => {
  //   const observer = new MutationObserver((mutList) => {
  //     mutList.forEach((mut) => {
  //       if (mut.type === 'childList') {
  //         const needCheck = Array.from(mut.addedNodes)
  //           .concat(Array.from(mut.removedNodes))
  //           .some((node) => {
  //             if (
  //               node instanceof HTMLElement &&
  //               (node.className.includes('cc-doc-toc') ||
  //                 node.querySelector('.cc-doc-toc'))
  //             )
  //               return true
  //             return false
  //           })
  //         if (needCheck) check()
  //       }
  //     })
  //   })
  //   observer.observe(ctnRef.current!, { childList: true, subtree: true })
  //   check()
  // }, [])

  return { ctnRef, headings, check };
}