React에서 지연된 약속 후크 만들기

독자 여러분 안녕하세요! 이 게시물에서는 React에서 지연된 약속 후크를 만들고 사용하는 방법을 보여 드리겠습니다. 의견 섹션에서 자유롭게 질문하거나 의견을 제시하십시오.
이 문서를 완전히 이해하려면 약속에 대한 지식이 있어야 합니다. 그렇지 않은 경우 this great article from MDN을 읽으십시오.
갑시다!

원칙



지연된 약속defined by the jQuery lib은 다음과 같습니다.

An object that can register multiple callbacks into callback queues, invoke callback queues, and relay the success or failure state of any synchronous or asynchronous function.



간단히 말해서 resolvereject와 같은 약속의 콜백을 저장하여 나중에 사용할 수 있으며 작업이 완료될 때까지 연기할 수 있음을 의미합니다.

사용 사례



다음 시나리오를 상상해 봅시다.
  • 제거 버튼이 있는 작업 목록 구성 요소가 있습니다
  • .
  • 제거 버튼을 클릭하면 확인 대화 상자가 나타납니다
  • .
  • 사용자가 제거를 확인하면 작업이 삭제됩니다. 그렇지 않으면 아무 일도 일어나지 않습니다

  • 다음은 이 아이디어의 초안입니다.



    이 시나리오의 코드를 다음과 같이 빌드할 수 있습니다.
  • 작업 목록 구성 요소

  • type ListProps = {
      allowDelete: () => Promise<boolean>;
    };
    
    const data = ['Task 1', 'Task 2', 'Task 3'];
    
    const List = ({ allowDelete }: ListProps) => {
      const [tasks, setTasks] = useState(data);
    
      const handleRemove = async (task: string) => {
        const canDelete = await allowDelete();
        if (!canDelete) return;
    
        const newTasks = tasks.filter((innerTask) => innerTask !== task);
        setTasks(newTasks);
      };
    
      return (
        <ul>
          {tasks.map((task) => (
            <li style={{ marginBottom: 10 }}>
              <span>{task}</span>
              <button style={{ marginLeft: 10 }} onClick={() => handleRemove(task)}>
                Remove
              </button>
            </li>
          ))}
        </ul>
      );
    };
    

  • 확인 대화 상자

  • type DialogProps = {
      isOpen: boolean;
      handleConfirm: () => void;
      handleClose: () => void;
    };
    
    const Dialog = ({ isOpen, handleConfirm, handleClose }: DialogProps) => {
      return (
        <dialog open={isOpen}>
          <div>Do you really want to remove this task?</div>
          <button onClick={handleConfirm}>Yes</button>
          <button onClick={handleClose}>No</button>
        </dialog>
      );
    };
    

  • 신청

  • const App = () => {
      const [isDialogOpen, setIsDialogOpen] = useState(false);
    
      const allowDelete = async () => {
        setIsDialogOpen(true);
        return true;
      };
    
      const handleConfirm = () => {
        setIsDialogOpen(false);
      };
    
      const handleClose = () => {
        setIsDialogOpen(false);
      };
    
      return (
        <Fragment>
          <List allowDelete={allowDelete} />
          <Dialog
            isOpen={isDialogOpen}
            handleConfirm={handleConfirm}
            handleClose={handleClose}
          />
        </Fragment>
      );
    };
    

    이 시나리오를 보면 작업을 제거할 수 있는지 여부를 결정하기 전에 목록 구성 요소가 사용자 개입을 기다려야 한다는 것이 분명합니다.

    하지만 문제가 있습니다! 이 코드를 실행하면 버그가 발생합니다. 사용자가 제거 버튼을 클릭하는 즉시 해당 작업은 사용자 동의 이전에 이미 삭제된 것입니다.


    구조에 대한 지연된 약속



    이 버그를 수정하려면 사용자 동의를 기다리도록 코드에 지시해야 하며 이는 지연된 약속을 생성하여 가능합니다.
    사용자 지정 후크를 만드는 방법을 단계별로 보여 드리겠습니다.
  • 먼저 defer 개체를 보유할 유형을 만듭니다. 이 개체에는 resolve 함수, reject 함수 및 이행될 promise의 세 가지 속성이 있어야 합니다. 아래에서 DeferredPromise가 약속 유형뿐만 아니라 resolve의 값 유형을 유추하는 제네릭 유형( DeferType )을 수신한다는 것을 알 수 있습니다.
    TypeScript 대신 일반 JavaScript를 사용하는 경우 이 단계를 건너뛸 수 있습니다.

  • type DeferredPromise<DeferType> = {
      resolve: (value: DeferType) => void;
      reject: (value: unknown) => void;
      promise: Promise<DeferType>;
    };
    

  • 다음으로 후크의 기능 정의를 시작하겠습니다. 이 훅은 defer 객체를 담을 간단한 ref로 시작합니다. 후크는 위에 정의된 것과 동일한 일반 유형을 수신합니다.

  • export function useDeferredPromise<DeferType>() {
      const deferRef = useRef<DeferredPromise<DeferType>>(null);
    
      return { deferRef: deferRef.current };
    }
    

  • 지금까지 너무 좋아요! 이제 defer 객체를 생성하는 함수로 후크를 증가시키겠습니다. 먼저 지연된 개체를 빌드합니다.

  • // Here is our deferred object that will hold the callbacks and the promise
    const deferred = {} as DeferredPromise<DeferType>;
    
    // We then create the main part of our defer object: the promise
    // Note that we take the promise's callbacks and inject them into our deferred object
    const promise = new Promise<DeferType>((resolve, reject) => {
       deferred.resolve = resolve;
       deferred.reject = reject;
    });
    
    // Finally, we inject the whole promise into the deferred object
    deferred.promise = promise;
    

  • 다음으로 새 지연 객체로 ref 후크를 업데이트합니다.

  • deferRef.current = deferred;
    

  • 이제 완전한 함수와 후크가 생겼습니다! 확인 해봐:

  • export function useDeferredPromise<DeferType>() {
      const deferRef = useRef<DeferredPromise<DeferType>>(null);
    
      const defer = () => {
        const deferred = {} as DeferredPromise<DeferType>;
    
        const promise = new Promise<DeferType>((resolve, reject) => {
          deferred.resolve = resolve;
          deferred.reject = reject;
        });
    
        deferred.promise = promise;
        deferRef.current = deferred;
        return deferRef.current;
      };
    
      return { defer, deferRef: deferRef.current };
    }
    

  • 좋아! 이제 후크가 완료되었습니다. 이제 우리가 발견한 버그를 해결하는 데 사용합시다!

  • 지연된 약속 후크 사용



    새 후크를 추가하여 애플리케이션 구성 요소를 수정해 보겠습니다. allowDelete 함수는 이제 연기된 약속을 반환하고 확인/삭제 함수는 이 연기된 약속을 해결합니다.

    const App = () => {
      const [isDialogOpen, setIsDialogOpen] = useState(false);
    
      // Here we declare the new hook
      // Note that we will resolve this promise using a boolean value (`true` or `false`). This is the generic type that we defined earlier.
      const { defer, deferRef } = useDeferredPromise<boolean>();
    
      const allowDelete = async () => {
        setIsDialogOpen(true);
        // Now a deferred promise is being returned
        return defer().promise;
      };
    
      const handleConfirm = () => {
        setIsDialogOpen(false);
        // If the user consents, the deferred promise is resolved with `true`
        deferRef.resolve(true);
      };
    
      const handleClose = () => {
        setIsDialogOpen(false);
        // If the user declines, the deferred promise is resolved with `false`
        deferRef.resolve(false);
      };
    
      return (
        <Fragment>
          <List allowDelete={allowDelete} />
          <Dialog
            isOpen={isDialogOpen}
            handleConfirm={handleConfirm}
            handleClose={handleClose}
          />
        </Fragment>
      );
    };
    


    이제 이 코드를 실행하면 버그가 수정되었음을 알 수 있습니다! 우리 코드는 작업을 제거하기 전에 사용자 동의를 성공적으로 기다립니다. 제거 작업이 거부되면 예상대로 아무 일도 일어나지 않습니다.



    마무리



    우리는 deferred Promise 후크를 처음부터 성공적으로 만들었고 매우 간단했습니다!
    나는 이 후크가 유용할 수 있는 사용 사례 중 하나만 보여주었지만 작업을 실행하기 전에 어떤 일이 일어나기를 기다려야 할 때마다 이것을 사용할 수 있습니다.
    여기에 이 ​​문서에 작성된 모든 코드에 대한 링크도 남겨둡니다: https://stackblitz.com/edit/react-ts-sukfgm?file=index.tsx

    한 가지 중요한 참고 사항: 약속을 연기한 후에는 약속을 해결하거나 거부하는 것을 잊지 마십시오. 그렇지 않으면 메모리 누수 문제가 발생할 수 있습니다.

    지금은 그게 다야! 궁금한 점이 있으면 댓글 섹션을 사용하는 것을 주저하지 마세요. 계속 주시하겠습니다!

    좋은 웹페이지 즐겨찾기