を使用して、対応するコンポーネント内の非同期コードの自動キャンセル


私は、実験的なuseAsyncEffectuseAsyncCallback(use-async-effect2 NPMパッケージ)を部品をアンマウントするとき、自動的に内部のasyncルーチンをキャンセルすることができるフックを作りました.また、ユーザによってキャンセル動作を高めることもできる.非同期ルーチンを正しくキャンセルすることは、周知の反応警告を避けるために重要です.Warning: Can't perform a React state update on an unmounted component. This is an no-op, but it indicates a memory leak in your application.それを働かせるために、ジェネレータはasync機能の交換として使われて、基本的に、yieldの代わりにawaitキーワードを使用するだけです.キャンセル可能な約束は、もう一つの私のプロジェクト―CPromise(cpromise2)によって提供されます.
  • useAsyncEffect最小限の例(注意してください.
  • import React, { useState } from "react";
    import { useAsyncEffect } from "use-async-effect2";
    import cpFetch from "cp-fetch"; //cancellable c-promise fetch wrapper
    
    export default function TestComponent(props) {
      const [text, setText] = useState("");
    
      useAsyncEffect(
        function* () {
          setText("fetching...");
          const response = yield cpFetch(props.url);
          const json = yield response.json();
          setText(`Success: ${JSON.stringify(json)}`);
        },
        [props.url]
      );
    
      return <div>{text}</div>;
    }
    
    エラー処理による
  • :
  • import React, { useState } from "react";
    import { useAsyncEffect, E_REASON_UNMOUNTED } from "use-async-effect2";
    import { CanceledError } from "c-promise2";
    import cpFetch from "cp-fetch";
    
    export default function TestComponent(props) {
      const [text, setText] = useState("");
    
      const cancel = useAsyncEffect(
        function* ({ onCancel }) {
          console.log("mount");
    
          this.timeout(5000);
    
          onCancel(() => console.log("scope canceled"));
    
          try {
            setText("fetching...");
            const response = yield cpFetch(props.url);
            const json = yield response.json();
            setText(`Success: ${JSON.stringify(json)}`);
          } catch (err) {
            CanceledError.rethrow(err, E_REASON_UNMOUNTED); //passthrough
            setText(`Failed: ${err}`);
          }
    
          return () => {
            console.log("unmount");
          };
        },
        [props.url]
      );
    
      return (
        <div className="component">
          <div className="caption">useAsyncEffect demo:</div>
          <div>{text}</div>
          <button onClick={cancel}>Abort</button>
        </div>
      );
    }
    
  • remountデモ
  • import React from "react";
    import { useState } from "react";
    import { useAsyncCallback } from "use-async-effect2";
    import { CPromise } from "c-promise2";
    
    export default function TestComponent() {
      const [text, setText] = useState("");
    
      const asyncRoutine = useAsyncCallback(function* (v) {
        setText(`Stage1`);
        yield CPromise.delay(1000);
        setText(`Stage2`);
        yield CPromise.delay(1000);
        setText(`Stage3`);
        yield CPromise.delay(1000);
        setText(`Done`);
        return v;
      });
    
      const onClick = () => {
        asyncRoutine(123).then(
          (value) => {
            console.log(`Result: ${value}`);
          },
          (err) => console.warn(err)
        );
      };
    
      return (
        <div className="component">
          <div className="caption">useAsyncCallback demo:</div>
          <button onClick={onClick}>Run async job</button>
          <div>{text}</div>
        </div>
      );
    }
    
    どんなフィードバックでも有り難いです😊