React useffect의 비동기 처리 및 정리
이상한 점과 개선된 점이 있으면 지적해 주세요.
제재
지정한 음원을 재생하는 구성 요소를 만듭니다.음원 지정 후 바로 재생, 지정 변경 후 원래의 소리를 멈추고 새로운 소리를 재생합니다.
설치로 useEffect에서 제작HTMLAudioElement하여 조작합니다.
다음은 코드와 동작을 확인할 수 있습니다.
불완전한 클린업 예
지정된 사운드를 재생성하는 어셈블리의 기본 뼈대는 다음과 같습니다.(Reactv18.0.0, Type Scriptv4.4.2 환경)
Example1.tsx
import { FC, useEffect } from "react";
type Props = { soundSrc: string };
export const Example1: FC<Props> = ({ soundSrc }) => {
useEffect(() => {
const audio = new Audio(soundSrc);
// audio.play()は、ロード完了時にfulfillされるPromiseを返し、再生を開始する
audio.play().catch((e) => alert(e));
return () => {
// ロード完了前にクリーンアップされる場合を考慮していない
audio.pause();
};
}, [soundSrc]);
return <p>Example1</p>;
};
이 코드는 audio.play()
불러오기 전에 청소를 실행하는 것을 고려하지 않았습니다.그럼에도 불구하고 마운트는 보통 짧은 시간 안에 이루어지기 때문에 그 정도의 시간 안에 구성 요소의 마운트 해제나 음원 변경이 없으면 이 문제는 드러나지 않는다.
Reactv18 StrictMode 시 useEffect
다시 말하면 Reactv18부터
<StrictMode>
에 둘러싸인 부품은 빌딩을 개발할 때만 설치할 때useffect라고 두 번 불린다.알기 쉬운 글: https://www.pandanoir.info/entry/2021/07/11/143303
문제점
이 기능을 통해 상기 구성 요소는 설치할 때useEffect->청소->useEffect의 속도로 실행되며 다음과 같은 오류가 발생합니다.
AbortError: The play() request was interrupted by a call to pause().
play()
의 준비가 완료되었을 때pause()
까지 불렀을 경우 상기 오류가 발생하여 재생이 취소됩니다.이 경우 이 같은 오류를 무시하면 결과가 올바른 행동으로 바뀌지만 바람직한 실행방식은 아니다.
인스턴스 개선
길어지지만 아래와 같이 두 개의 로고를 사용하여 업로드 전에 정리 처리할 수 있습니다.
Example3.tsx
useEffect(() => {
let isLoaded = false;
let isCanceled = false;
const audio = new Audio(soundSrc);
audio
.play()
.then(() => {
if (isCanceled) {
// キャンセル済みの場合、ここで音停止
audio.pause();
} else {
isLoaded = true;
}
})
.catch((e) => alert(e));
return () => {
// ロード済みであれば音停止、そうでなければキャンセルフラグをセット
if (isLoaded) {
audio.pause();
} else {
isCanceled = true;
}
};
}, [soundSrc]);
※ isLoaded
의 로고만 사용해 제어할 경우 소리가 중복되므로 주의가 필요합니다(CodeSandbox의Example2
.useEffect는 동기화 함수만 설정할 수 있습니다
참고로 전체를 async 함수로 설정하면 아래처럼 간단하게 쓸 수 있지만 useEffect는 동기화 함수만 설정할 수 있기 때문에 이걸 쓸 수 없습니다.
// NG
useEffect(async () => {
const audio = new Audio(soundSrc);
try {
await audio.play();
} catch (e) {
return alert(e);
}
// audio.play()をawaitしてからクリーンアップ関数を返す
return () => audio.pause();
}, [soundSrc]);
총결산
useEffect에서 청소가 필요한 비동기 처리를 할 때 비동기 처리가 완료되기 전에 청소를 실행해야 하는 상황을 고려해야 하는 예를 보여 줍니다.
이번에 StrictMode를 사용해서 문제점을 발견했습니다. 가능하면 StrictMode를 사용해서useEffect를 사용해야 하는지 확인하는 것이 좋습니다.
Reference
이 문제에 관하여(React useffect의 비동기 처리 및 정리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/k_kind/articles/19d0f12e5db6fb텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)