Let's create a React File Manager Chapter VII: Listing Sidebar
Tags: react, typescript, mongez
Published: 2022-09-13 17:00:43

---
title: Let's create a React File Manager Chapter VII: Listing Sidebar 
published: true
description: 
series: File Manager React Mongez
tags: react, typescript, mongez
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/314szylzr6lwrc0bizyb.png
# Use a ratio of 100:42 for best results.
---

Now we can see in the previous article that we loaded the root directory contents, now let's display them in the sidebar.

But before we do this, let's enhance out directory loading in the file manager as we later will need a function to load the selected directory, so let's create `load` function in the `FileManager` component.

```tsx
// FileManager.tsx
...
  // load the given directory path
  const load = (path: string) => {
    setIsLoading(true);
    fileManager
      .load(path)
      .then(node => {
        setCurrentDirectoryNode(node);
      })
      .finally(() => {
        setIsLoading(false);
      });
  };

  // load root directory
  useEffect(() => {
    if (!rootPath || !open) return;

    setIsLoading(true);

    fileManager.load(rootPath).then(directoryNode => {
      setIsLoading(false);
      setCurrentDirectoryNode(directoryNode);
    });
  }, [rootPath, fileManager, open]);
```

We create the load function and now we need to call it in the `useEffect` hook to load the root directory.

```tsx
// FileManager.tsx

  // load root directory
  useEffect(() => {
    if (!rootPath || !open) return;

    load(rootPath);
  }, [rootPath, fileManager, open]);
```

Now the eslint will complain about the `load` function not being in the dependencies array, so let's add it but we need to wrap it in a `useCallback` to prevent reloading the effect multiple times.

```tsx
// FileManager.tsx

  // load the given directory path
  const load = useCallback(
    (path: string) => {
      setIsLoading(true);
      fileManager
        .load(path)
        .then(node => {
          setCurrentDirectoryNode(node);
        })
        .finally(() => {
          setIsLoading(false);
        });
    },
    [fileManager],
  );

  // load root directory
  useEffect(() => {
    if (!rootPath || !open) return;

    load(rootPath);
  }, [rootPath, fileManager, open, load]);
```

One more thing to do is we need to store the `rootDirectoryNode` in a state so it will be available to the `Sidebar` component.

```tsx
// FileManager.tsx
...
  const [currentDirectoryNode, setCurrentDirectoryNode] = useState<Node>();
  const [rootDirectoryNode, setRootDirectoryNode] = useState<Node>();
...
  // load the given directory path
  const load = useCallback(
    (path: string, isRoot = false) => {
      setIsLoading(true);
      fileManager
        .load(path)
        .then(node => {
          setCurrentDirectoryNode(node);
          if (isRoot) {
            setRootDirectoryNode(node);
          }
        })
        .finally(() => {
          setIsLoading(false);
        });
    },
    [fileManager],
  );
  
  // load root directory
  useEffect(() => {
    if (!rootPath || !open) return;

    load(rootPath, true);
  }, [rootPath, fileManager, open, load]);

```

Now our FileManager will look like:

```tsx
// FileManager.tsx
import { Grid, Modal } from "@mantine/core";
import BaseFileManager from "app/file-manager/utils/FileManager";
import { useCallback, useEffect, useRef, useState } from "react";
import { Node } from "../../types/FileManager.types";
import Content from "./Content";
import { BodyWrapper } from "./FileManager.styles";
import { FileManagerProps } from "./FileManager.types";
import Sidebar from "./Sidebar";
import Toolbar from "./Toolbar";

export default function FileManager({
  open,
  onClose,
  rootPath,
}: FileManagerProps) {
  const [isLoading, setIsLoading] = useState(true);
  const [currentDirectoryNode, setCurrentDirectoryNode] = useState<Node>();
  const [rootDirectoryNode, setRootDirectoryNode] = useState<Node>();

  const { current: fileManager } = useRef(new BaseFileManager());

  // load the given directory path
  const load = useCallback(
    (path: string, isRoot = false) => {
      setIsLoading(true);

      fileManager.load(path).then(node => {
        setCurrentDirectoryNode(node);

        setIsLoading(false);
        if (isRoot) {
          setRootDirectoryNode(node);
        }
      });
    },
    [fileManager],
  );

  // load root directory
  useEffect(() => {
    if (!rootPath || !open) return;

    load(rootPath, true);
  }, [rootPath, fileManager, open, load]);

  return (
    <>
      <Modal size="xl" opened={open} onClose={onClose}>
        <Toolbar />
        <BodyWrapper>
          <Grid>
            <Grid.Col span={3}>
              <Sidebar />
            </Grid.Col>
            <Grid.Col span={9}>
              <Content />
            </Grid.Col>
          </Grid>
        </BodyWrapper>
      </Modal>
    </>
  );
}

FileManager.defaultProps = {
  rootPath: "/",
};
```

## Sidebar

Now let's update our `Sidebar` component as we need to display the root directory contents, we need to pass to to it the root node.

```tsx
// Sidebar.tsx
import { Card } from "@mantine/core";
import { Node } from "../../../types/FileManager.types";

export type SidebarProps = {
  rootDirectory?: Node;
};

export default function Sidebar({ rootDirectory }: SidebarProps) {
  return (
    <>
      <Card shadow="sm">
        <div>Sidebar</div>
      </Card>
    </>
  );
}
```

Now let's loop over the root directory to display its children content, but there is a catch here, we need to display the children of the root directory only if it is a directory.

```tsx
// Sidebar.tsx
import { Card } from "@mantine/core";
import { useMemo } from "react";
import { Node } from "../../../types/FileManager.types";

export type SidebarProps = {
  rootDirectory?: Node;
};

export default function Sidebar({ rootDirectory }: SidebarProps) {
  const rootChildren = useMemo(() => {
    return rootDirectory?.children?.filter(child => child.isDirectory);
  }, [rootDirectory]);

  if (!rootDirectory) return null;

  return (
    <>
      <Card shadow="sm">
        <div>Sidebar</div>
      </Card>
    </>
  );
}
```

We create a memo to store root directory children with simple filter, get only children nodes that has `isDirectory` property set to `true`.

Now let's go back to our `FileManager` component and pass the `rootDirectoryNode` to the `Sidebar` component.

```diff
// FileManager.tsx

<Grid.Col span={3}>
-    <Sidebar />
+    <Sidebar rootDirectory={rootDirectoryNode} />
</Grid.Col>
```

Now you should see something like this:

![Sidebar](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w8fct4zld2e5x9iutm7y.png)

## Display Sidebar Nodes

Let's enhance our code a little bit and create a sidebar node for each node so we can get more controls and code get less complex,  we'll call it `SidebarNode.tsx`, we'll create it in the same directory of `Sidebar`.

```tsx
// SidebarNode.tsx
import { Node } from "../../../types/FileManager.types";

export type SidebarNodeProps = {
  node: Node;
};

export default function SidebarNode({ node }: SidebarNodeProps) {
  return (
    <>
      <div>{node.name}</div>
    </>
  );
}
```

Now let's update our `Sidebar` component to display the `SidebarNode` for each node.

```tsx
// Sidebar.tsx
import { Card } from "@mantine/core";
import { useMemo } from "react";
import { Node } from "../../../types/FileManager.types";
import SidebarNode from "./SidebarNode";

export type SidebarProps = {
  rootDirectory?: Node;
};

export default function Sidebar({ rootDirectory }: SidebarProps) {
  const rootChildren = useMemo(() => {
    return rootDirectory?.children?.filter(child => child.isDirectory);
  }, [rootDirectory]);

  if (!rootDirectory) return null;

  return (
    <>
      <Card shadow="sm">
        {rootChildren?.map(child => (
          <SidebarNode key={child.path} node={child} />
        ))}
      </Card>
    </>
  );
}
```

Now it looks like this:

![File Manager](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9gfcc12i0vohmpf5v3p4.png)

In the next article, we'll make more improvements in our sidebar like adding icons and also add the home root as well to be displayed at the top of the sidebar.

## Article Repository

You can see chapter files in [Github Repository](https://github.com/hassanzohdy/file-manager-react/tree/6-fetching-directories-files)

> Don't forget the `main` branch has the latest updated code.

Salam.