React에서 지연된 약속 후크 만들기
23902 단어 hooksjavascripttypescriptreact
이 문서를 완전히 이해하려면 약속에 대한 지식이 있어야 합니다. 그렇지 않은 경우 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.
간단히 말해서
resolve
및 reject
와 같은 약속의 콜백을 저장하여 나중에 사용할 수 있으며 작업이 완료될 때까지 연기할 수 있음을 의미합니다.사용 사례
다음 시나리오를 상상해 봅시다.
다음은 이 아이디어의 초안입니다.
이 시나리오의 코드를 다음과 같이 빌드할 수 있습니다.
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>
);
};
이 시나리오를 보면 작업을 제거할 수 있는지 여부를 결정하기 전에 목록 구성 요소가 사용자 개입을 기다려야 한다는 것이 분명합니다.
하지만 문제가 있습니다! 이 코드를 실행하면 버그가 발생합니다. 사용자가 제거 버튼을 클릭하는 즉시 해당 작업은 사용자 동의 이전에 이미 삭제된 것입니다.
구조에 대한 지연된 약속
이 버그를 수정하려면 사용자 동의를 기다리도록 코드에 지시해야 하며 이는 지연된 약속을 생성하여 가능합니다.
사용자 지정 후크를 만드는 방법을 단계별로 보여 드리겠습니다.
resolve
함수, reject
함수 및 이행될 promise
의 세 가지 속성이 있어야 합니다. 아래에서 DeferredPromise
가 약속 유형뿐만 아니라 resolve의 값 유형을 유추하는 제네릭 유형( DeferType
)을 수신한다는 것을 알 수 있습니다.TypeScript 대신 일반 JavaScript를 사용하는 경우 이 단계를 건너뛸 수 있습니다.
type DeferredPromise<DeferType> = {
resolve: (value: DeferType) => void;
reject: (value: unknown) => void;
promise: Promise<DeferType>;
};
export function useDeferredPromise<DeferType>() {
const deferRef = useRef<DeferredPromise<DeferType>>(null);
return { deferRef: deferRef.current };
}
// 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;
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
한 가지 중요한 참고 사항: 약속을 연기한 후에는 약속을 해결하거나 거부하는 것을 잊지 마십시오. 그렇지 않으면 메모리 누수 문제가 발생할 수 있습니다.
지금은 그게 다야! 궁금한 점이 있으면 댓글 섹션을 사용하는 것을 주저하지 마세요. 계속 주시하겠습니다!
Reference
이 문제에 관하여(React에서 지연된 약속 후크 만들기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/vicnovais/creating-a-deferred-promise-hook-in-react-39jh텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)