React와 Typescript를 사용하여 처음부터 파일 관리자를 만들어 봅시다 3장: 루트 디렉토리 가져오기

28430 단어 typescriptmongezreact
이제 기본 설정이 준비되었습니다. 파일 관리자를 위한 간단한 목업 API를 만들어 보겠습니다.

파일 관리자 서비스


file-manager-service.ts 디렉토리 아래에 file-manager/services를 생성한 다음 설정해 봅시다.

// file-manager-service.ts
export class FileManagerService implements FileManagerServiceInterface {

}


아직 명확하게 정의되지 않은 인터페이스FileManagerServiceInterface를 구현하는 빈 클래스를 방금 만들었으므로 정의해 보겠습니다.

FileManagerService인터페이스 인터페이스



여기에서 파일 관리자에서 어떤 요청이 사용될 수 있는지 생각해 봅시다. 모든 요청을 나열하거나 최소한 기본 요청만 나열해 보겠습니다.
  • 디렉토리 내용 나열
  • 파일 업로드
  • 디렉터리/파일 이름 변경
  • 디렉터리/파일 삭제
  • 디렉터리 만들기
  • 디렉터리/파일 이동
  • 디렉터리/파일 복사

  • 그래서 우리는 6-7개의 요청을 좋아합니다. 그들의 인터페이스를 만들어 봅시다.
    file-manager/types로 이동하여 FileManagerServiceInterface.ts 파일 생성

    // file-manager/types/FileManagerServiceInterface.ts
    export default interface FileManagerServiceInterface {
      /**
       * List directory contents for the given path
       */
      list(directoryPath: string): Promise<any>;
    
      /**
       * Create new directory
       *
       * First parameter will be the directory name,
       * second parameter will be the directory path that will be created into.
       */
      createDirectory(directoryName: string, saveTo: string): Promise<any>;
    
      /**
       * Delete directories/files
       */
      delete(paths: string[]): Promise<any>;
    
      /**
       * Rename directory | file
       *
       * The first parameter will be the old path,
       * the second parameter will be the new path.
       */
      rename(path: string, newPath: string): Promise<any>;
    
      /**
       * Copy the given files/directories to the given destination
       */
      copy(paths: string[], destination: string): Promise<any>;
    
      /**
       * Move the given files/directories to the given destination
       */
      move(paths: string[], destination: string): Promise<any>;
    
      /**
       * Upload the given files into the given directory path
       */
      upload(files: File[], directoryPath: string): Promise<any>;
    }
    


    이제 FileManagerService 파일에서 인터페이스를 가져오겠습니다.

    // file-manager-service.ts
    import FileManagerServiceInterface from "../types/FileManagerServiceInterface";
    
    export class FileManagerService implements FileManagerServiceInterface {}
    


    물론 이제 Typescript 컴파일러는 우리가 이러한 메서드를 구현하지 않았다고 불평할 것입니다.

    하지만 이 작업을 수행하기 전에 일부 데이터를 위조할 수 있도록 먼저 설치Faker해 보겠습니다.
    yarn add -D @faker-js/faker
    이제 서비스 클래스로 돌아가 봅시다.

    import FileManagerServiceInterface from "../types/FileManagerServiceInterface";
    
    export class FileManagerService implements FileManagerServiceInterface {
      /**
       * {@inheritDoc}
       */
      public list(directoryPath: string): Promise<any> {
        return new Promise(resolve => {
          resolve({
            data: {
              nodes: listNodes(),
            },
          });
        });
      }
    }
    


    모의axios 응답 형태를 약속했기 때문에 목업 API 작업이 끝나면 언제든지 실제 API로 쉽게 교체할 수 있습니다.

    If you've a real API to work with, i'll be pleased to use in the series :)



    list 메서드는 nodes의 목록을 배열로 반환합니다.

    이제 faker에서 listNodes 함수를 생성해 보겠습니다. utils 파일 아래의 data.ts 디렉토리에 생성됩니다.

    // file-manager/utils/data.ts
    import { faker } from "@faker-js/faker";
    import { DirectoryNode, Node } from "../types/FileManager.types";
    
    export function newNode(): Node {
      const node: Node | DirectoryNode = {
        name: faker.system.fileName(),
        path: faker.system.filePath(),
        size: faker.datatype.number({ min: 1, max: 100000 }),
        isDirectory: faker.datatype.boolean(),
      };
    
      if (node.isDirectory) {
        (node as DirectoryNode).children = listNodes(3);
      }
    
      return node;
    }
    
    export function listNodes(maxNodes = 10): Node[] {
      return faker.datatype
        .array(faker.datatype.number({ min: 1, max: maxNodes }))
        .map(newNode);
    }
    


    두 번째 함수listNodes에서는 노드 목록을 무작위로 생성하고 최대 생성 노드인 하나의 매개변수를 허용합니다. 이것은 중요하므로 자식 노드를 생성할 때 무한 루프에 빠지지 않도록 3개의 자식 노드로만 최대화합니다. (newNode 함수에서).
    newNode 함수는 임의의 노드 데이터를 생성하는 데 사용되며 노드를 Node 또는 DirectoryNode로 설정합니다.

    실제로 Node로만 작업하고 그 안에 children 속성을 설정하여 노드가 디렉토리인 경우 자식을 가질 수 있도록 합시다.
    types/FileManager.types.ts로 이동하여 FileNodeDirectoryNode를 제거한 다음 Node를 업데이트합니다.

    // file-manager/types/FileManager.types.ts
    /**
     * File Manager node is the primary data structure for the File Manager.
     * It can be a directory or a file.
     * It contains the following properties:
     */
    export type Node = {
      /**
       * Node Name
       */
      name: string;
      /**
       * Node full path to root
       */
      path: string;
      /**
       * Node size in bits
       */
      size: number;
      /**
       * Is node directory
       */
      isDirectory: boolean;
      /**
       * Node children
       * This should be present (event with empty array) if the node is directory
       */
      children?: Node[];
    };
    


    이렇게 하면 코드가 덜 혼란스러워지므로 노드는 두 가지 유형의 모양, 즉 자식을 포함하는 디렉터리 모양과 자식이 없는 파일 모양을 가질 수 있습니다.
    FileManager 클래스로 이동하여 현재 디렉터리 노드를 업데이트해 보겠습니다.

    // file-manager/utils/FileManager.ts
    import { Node } from "../types/FileManager.types";
    
    export default class FileManager {
      /**
       * Root path
       */
      protected rootPath = "/";
    
      /**
       * Current directory path
       */
      protected currentDirectoryPath = "/";
    
      /**
       * Current directory node
       */
      protected currentDirectoryNode?: Node;
    }
    


    마지막으로 utils/data.ts 파일을 다시 업데이트하겠습니다.

    // file-manager/utils/data.ts
    import { faker } from "@faker-js/faker";
    import { Node } from "../types/FileManager.types";
    
    export function newNode(): Node {
      const node: Node = {
        name: faker.system.fileName(),
        path: faker.system.filePath(),
        size: faker.datatype.number({ min: 1, max: 100000 }),
        isDirectory: faker.datatype.boolean(),
      };
    
      if (node.isDirectory) {
        node.children = listNodes(3);
      }
    
      return node;
    }
    
    export function listNodes(maxNodes = 10): Node[] {
      return faker.datatype
        .array(faker.datatype.number({ min: 1, max: maxNodes }))
        .map(newNode);
    }
    


    이제 코드가 훨씬 깔끔해졌습니다.

    Pro Tip: you don't get the perfect code from the first time, that's why we're going to enhance and develop our code gradually as we progress in our project.



    파일 관리자 서비스로 돌아갑니다.

    import FileManagerServiceInterface from "../types/FileManagerServiceInterface";
    import { listNodes } from "../utils/data";
    
    export class FileManagerService implements FileManagerServiceInterface {
      /**
       * {@inheritDoc}
       */
      public list(directoryPath: string): Promise<any> {
        return new Promise(resolve => {
          resolve({
            data: {
              nodes: listNodes(),
            },
          });
        });
      }
    
      /**
       * {@inheritDoc}
       */
      public createDirectory(directoryName: string, saveTo: string): Promise<any> {
        throw new Error("Method not implemented.");
      }
      /**
       * {@inheritDoc}
       */
      public delete(paths: string[]): Promise<any> {
        throw new Error("Method not implemented.");
      }
      /**
       * {@inheritDoc}
       */
      public rename(path: string, newPath: string): Promise<any> {
        throw new Error("Method not implemented.");
      }
      /**
       * {@inheritDoc}
       */
      public copy(paths: string[], destination: string): Promise<any> {
        throw new Error("Method not implemented.");
      }
      /**
       * {@inheritDoc}
       */
      public move(paths: string[], destination: string): Promise<any> {
        throw new Error("Method not implemented.");
      }
      /**
       * {@inheritDoc}
       */
      public upload(files: File[], directoryPath: string): Promise<any> {
        throw new Error("Method not implemented.");
      }
    }
    


    나머지 코드는 vscode 기능을 사용하여 자동 주입되도록 만들었으므로 컴파일러 오류가 발생하지 않습니다.

    지금까지 너무 좋았어, 이 시점에서 멈출거야.
    HomePage 구성 요소에서 결과를 볼 수 있습니다.

    구성 요소로 이동하여 내부에 다음 코드를 붙여넣은 다음 콘솔에서 결과를 확인합니다.

    // home/components/HomePage/HomePage.tsx
    import Helmet from "@mongez/react-helmet";
    import { FileManagerService } from "app/file-manager/services/file-manager-service";
    
    const fileManager = new FileManagerService();
    
    export default function HomePage() {
      fileManager.list("/").then(response => {
        console.log(response.data);
      });
      return (
        <>
          <Helmet title="home" appendAppName={false} />
          <h1>Welcome To Home Page</h1>
        </>
      );
    }
    


    기사 저장소



    Github Repository에서 챕터 파일을 볼 수 있습니다.

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

    좋은 웹페이지 즐겨찾기