diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebar/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebar/index.tsx
index 6c5c9f7b46..9842fd52d4 100644
--- a/packages/docusaurus-theme-classic/src/theme/DocSidebar/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/DocSidebar/index.tsx
@@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
-import React, {useState, useCallback, useEffect, useRef, useMemo} from 'react';
+import React, {useState, useCallback, useEffect, useRef, memo} from 'react';
import clsx from 'clsx';
import {useThemeConfig, isSamePath} from '@docusaurus/theme-common';
import useUserPreferencesContext from '@theme/hooks/useUserPreferencesContext';
@@ -44,6 +44,32 @@ const isActiveSidebarItem = (item, activePath) => {
return false;
};
+// Optimize sidebar at each "level"
+// TODO this item should probably not receive the "activePath" props
+// TODO this triggers whole sidebar re-renders on navigation
+const DocSidebarItems = memo(function DocSidebarItems({
+ items,
+ ...props
+}: any): JSX.Element {
+ return items.map((item, index) => (
+
+ ));
+});
+
+function DocSidebarItem(props): JSX.Element {
+ switch (props.item.type) {
+ case 'category':
+ return ;
+ case 'link':
+ default:
+ return ;
+ }
+}
+
function DocSidebarItemCategory({
item,
onItemClick,
@@ -104,8 +130,7 @@ function DocSidebarItemCategory({
+ })}>
- {items.map((childItem) => (
-
- ))}
+
);
@@ -172,37 +194,24 @@ function DocSidebarItemLink({
);
}
-function DocSidebarItem(props): JSX.Element {
- switch (props.item.type) {
- case 'category':
- return ;
- case 'link':
- default:
- return ;
- }
+function useShowAnnouncementBar() {
+ const {isAnnouncementBarClosed} = useUserPreferencesContext();
+ const [showAnnouncementBar, setShowAnnouncementBar] = useState(
+ !isAnnouncementBarClosed,
+ );
+ useScrollPosition(({scrollY}) => {
+ if (!isAnnouncementBarClosed) {
+ setShowAnnouncementBar(scrollY === 0);
+ }
+ });
+ return showAnnouncementBar;
}
-function DocSidebar({
- path,
- sidebar,
- sidebarCollapsible = true,
- onCollapse,
- isHidden,
-}: Props): JSX.Element | null {
+function useResponsiveSidebar() {
const [showResponsiveSidebar, setShowResponsiveSidebar] = useState(false);
- const [showAnnouncementBar, setShowAnnouncementBar] = useState(true);
- const {
- navbar: {hideOnScroll},
- hideableSidebar,
- } = useThemeConfig();
- const {isAnnouncementBarClosed} = useUserPreferencesContext();
- useScrollPosition(({scrollY}) => {
- setShowAnnouncementBar(scrollY === 0);
- });
-
useLockBodyScroll(showResponsiveSidebar);
- const windowSize = useWindowSize();
+ const windowSize = useWindowSize();
useEffect(() => {
if (windowSize === windowSizes.desktop) {
setShowResponsiveSidebar(false);
@@ -216,19 +225,99 @@ function DocSidebar({
},
[setShowResponsiveSidebar],
);
- const sidebarItems = useMemo(
- () =>
- sidebar.map((item) => (
-
- )),
- [sidebar, sidebarCollapsible, path, closeResponsiveSidebar],
+
+ const toggleResponsiveSidebar = useCallback(() => {
+ setShowResponsiveSidebar(!showResponsiveSidebar);
+ }, [setShowResponsiveSidebar]);
+
+ return {
+ showResponsiveSidebar,
+ closeResponsiveSidebar,
+ toggleResponsiveSidebar,
+ };
+}
+
+function HideableSidebarButton({onClick}) {
+ return (
+
);
+}
+
+function ResponsiveSidebarButton({responsiveSidebarOpened, onClick}) {
+ return (
+
+ );
+}
+
+function DocSidebar({
+ path,
+ sidebar,
+ sidebarCollapsible = true,
+ onCollapse,
+ isHidden,
+}: Props): JSX.Element | null {
+ const showAnnouncementBar = useShowAnnouncementBar();
+ const {
+ navbar: {hideOnScroll},
+ hideableSidebar,
+ } = useThemeConfig();
+ const {isAnnouncementBarClosed} = useUserPreferencesContext();
+
+ const {
+ showResponsiveSidebar,
+ closeResponsiveSidebar,
+ toggleResponsiveSidebar,
+ } = useResponsiveSidebar();
return (
-
-
+
+
- {hideableSidebar && (
-
- )}
+ {hideableSidebar && }
);
}