React-pdf: マウントされていないコンポーネントでReact状態の更新を実行できません

作成日 2019年02月13日  ·  19コメント  ·  ソース: wojtekmaj/react-pdf

始める前に-チェックリスト

  • [x] React-PDFバージョン用に作成されたドキュメントの指示に従いました
  • [x]このバグがまだ報告されていないかどうかを確認しました
  • [x]問題が既知の問題にリストされていないかどうかを確認し

説明

次のコンポーネントでは、次の警告が表示されます。

警告:マウントされていないコンポーネントでReact状態の更新を実行することはできません。

screenshot 2019-02-13 at 18 59 36

再現する手順

これは問題のあるコンポーネントです。

class Pdf extends Component {
  state = { numPages: 0 }

  onDocumentLoad = ({ numPages }) => this.setState({ numPages })

  render() {
    const { numPages } = this.state
    const { url } = this.props

    const headers = { withCredentials: true }

    return (
      <Document file={{ headers, url }} onLoadSuccess={this.onDocumentLoad}>
        {range(0, numPages).map(index => (
          <Page key={index} pageIndex={index} />
        ))}
      </Document>
    )
  }
}

予想される行動

setStateを削除すると、PDFは正しくレンダリングされますが、ページ数に関する情報が失われます。

追加情報

これはREADMEの例であり、v4にアップグレードする前は完全に機能していました。

環境

  • React-PDFバージョン: 4.0.2
  • Reactバージョン: 16.8.1
  • Webpackバージョン(該当する場合): 4.29.3
bug

最も参考になるコメント

next.jsプロジェクトでこのライブラリを使用しているときに、この問題が発生しました。

私の理解では、エラーは再レンダリング中に発生します-私の場合、 onLoadSuccessが呼び出されてnumberOfPagesが更新されたときです。

私の現在の解決策は、 useMemoを使用してファイルオブジェクトをメモ化することです。 これを行うと、エラーは完全に消えます。

function PreviewPDF(props) {
  const [numberOfPages, setNumberOfPages] = useState(null);
  const [pageNumber, setPageNum] = useState(1);
  const file = useMemo(
    () => ({ url: props.fileSrc, withCredentials: true }),
    []
  );

  return (
    <Portal>
      <Document
          file={file}
          onLoadSuccess={({ numPages }) => setNumberOfPages(numPages)}
          options={{ cMapUrl: '/_next/cmaps/', cMapPacked: true }}
        >
          <Page pageNumber={pageNumber} />
      </Document>
    </Portal>
  );
}

props.fileSrcが必要な場合。

お役に立てれば。

全てのコメント19件

こんにちは@Kerumen

これを試して:

onDocumentLoad = (document) => {
  const { numPages } = document;
  this.setState({
    numPages,
  });
};

こちらの例をご覧ください

@Kerumenあなたはそれを機能させましたか?

@ Maxhou00
バンドルから直接ファイルをロードする場合は正常に機能します。 しかし、URLからPDFをロードすると、同じ問題が発生します。

私はアプローチが言及しようとした、ここでそれがロードを続けている上記とネットワークのコールを保つのと同じ問題に直面します。
screen shot 2019-02-18 at 1 35 51 pm

「警告:マウントされていないコンポーネントでReact状態の更新を実行できません。これは動作しませんが、アプリケーションのメモリリークを示しています。修正するには、componentWillUnmountメソッドのすべてのサブスクリプションと非同期タスクをキャンセルします。
PageInternal内(Context.Consumerによって作成)
ページ内(Test.js:30)」

@qaisershehzadおそらく、すべてのレンダリングで新しいfileオブジェクトを定義していますか? #308を参照

@wojtekmaj私はこれをやっています:
screen shot 2019-02-18 at 4 55 52 pm

@wojtekmaj私はこのようにすることでそれを機能させることができます:
screen shot 2019-02-18 at 5 20 07 pm

また、同じ「マウントされていないコンポーネントの状態更新に反応する」というメッセージが表示されました。 ただし、これは、react-pdfで複数ページのPDFを開いていて、最初のページが読み込まれる前に1つのページから別のページに移動していたときに発生したようです。

私の「修正」は、ページの読み込み時に「on​​RenderSuccess」イベントが発生するまで、すべてのコントロールを無効にすることでした。 新しいページを読み込もうとします。すべてのコントロールを無効にし、「onRenderSuccess」を待ちます。 しかし、これがやり過ぎかどうかはわかりません。 @wojtekmaj :これは正しいことのように聞こえますか?

PageInternal unmountの設定状態をキャンセルできるはずなので、これは比較的簡単に対処できるバグのように聞こえます。 すべてのコントロールを無効にする価値はないと思います-バグ自体は何もクラッシュしません-しかし、今のところこのメッセージを本当に見たくない場合は、それを行うべき回避策です:)

コメントありがとうございます。 そのバグが修正されるのを楽しみにしています。

こんにちは@peterkmurphy 、私は同じ問題を抱えていますが、onRenderSuccessが呼び出されるまでコントロールを無効にすることの意味がわかりません。 私はこれをやっています:

onRenderSuccess = () => {
  this.setState({
    renderSuccess: true
  });
};

...

{renderSuccess && numPages && numPages.lengh > 1 && (
  <>
    <p>
      Page {pageNumber || (numPages ? 1 : '--')} of{' '}
      {numPages || '--'}
    </p>
    <button
      type="button"
      disabled={pageNumber <= 1}
      onClick={this.previousPage}
    >
      Previous
    </button>
    <button
      type="button"
      disabled={pageNumber >= numPages}
      onClick={this.nextPage}
    >
      Next
    </button>
  </>
)}

ソリューションについて詳しく教えていただけますか? ありがとうございました :)

これに対する解決策を聞くことにも興味があります。 React Hooksを使用しているコンポーネントにエラーが表示されているため、それがミックスにどのように影響するかわかりません。

next.jsプロジェクトでこのライブラリを使用しているときに、この問題が発生しました。

私の理解では、エラーは再レンダリング中に発生します-私の場合、 onLoadSuccessが呼び出されてnumberOfPagesが更新されたときです。

私の現在の解決策は、 useMemoを使用してファイルオブジェクトをメモ化することです。 これを行うと、エラーは完全に消えます。

function PreviewPDF(props) {
  const [numberOfPages, setNumberOfPages] = useState(null);
  const [pageNumber, setPageNum] = useState(1);
  const file = useMemo(
    () => ({ url: props.fileSrc, withCredentials: true }),
    []
  );

  return (
    <Portal>
      <Document
          file={file}
          onLoadSuccess={({ numPages }) => setNumberOfPages(numPages)}
          options={{ cMapUrl: '/_next/cmaps/', cMapPacked: true }}
        >
          <Page pageNumber={pageNumber} />
      </Document>
    </Portal>
  );
}

props.fileSrcが必要な場合。

お役に立てれば。

@qaisershehzad私はそれをほぼ2日間苦労してきました。 ファイルオブジェクト全体を状態にするというあなたのアプローチは、ついに私を助けました。 ありがとう

オブジェクトのメモ化/状態の維持は、正しい推奨ソリューションです。 より良い解決策が得られるまで、その問題についてより良いドキュメントを作成するようにします(上記で参照したコミットのように、進行中ですが、「正常に機能しているようです」)。

コンポーネントをアンマウントすると、リクエストがキャンセルされます。 その後、約束は拒否されます。
https://github.com/wojtekmaj/react-pdf/blob/590077862132d86da44ac0dc59fc99aaf1e99224/src/Page.jsx#L77

  componentWillUnmount() {
    const { unregisterPage } = this.props;

    callIfDefined(
      unregisterPage,
      this.pageIndex,
    );

    cancelRunningTask(this.runningTask);
  }

loadPage
https://github.com/wojtekmaj/react-pdf/blob/590077862132d86da44ac0dc59fc99aaf1e99224/src/Page.jsx#L264

    try {
      const cancellable = makeCancellable(pdf.getPage(pageNumber));
      this.runningTask = cancellable;
      const page = await cancellable.promise;
      this.setState({ page }, this.onLoadSuccess);
    } catch (error) {
      this.setState({ page: false });
      this.onLoadError(error);
    }

ただし、エラーを分類して、ネットワークエラーまたはキャンセルされたタスクであるかどうかを判断する必要があると思います。 アンマウントライフサイクルメソッドによってキャンセルされた場合は、setStateなどを実行しないでください。
以下のコードのように:

    try {
      const cancellable = makeCancellable(pdf.getPage(pageNumber));
      this.runningTask = cancellable;
      const page = await cancellable.promise;
      this.setState({ page }, this.onLoadSuccess);
    } catch (error) {
        if (error.msg && error.msg === 'cancelled') {
            return;
        }

      this.setState({ page: false });
      this.onLoadError(error);
    }

@wojtekmaj

マウントされたコンポーネントでnumPagesを更新しようとすると、同じエラーが発生します。
「警告:マウントされていないコンポーネントでReact状態の更新を実行できません。」

すでに状態のファイルを使用しています-問題はonDocumentLoadSuccessを使用している場合のみです:
onDocumentLoadSuccess = (document) => { console.log('doc loaded!') if(this.state.numPages == null) { this.setState({ numPages: document.numPages }) } }

うーん、onDocumentLoadSuccessを再現しましたが、エラー@ scottie-schneiderが表示されません:(見てみませんか?

https://codesandbox.io/s/little-hooks-bbgek

こんにちは、
同じ問題が発生していますが、Reduxからロードしているバッファーを使用すると、ループに入ります。 これは、ドキュメントの読み込みが成功したときに状態を更新するたびに発生します。

うーん、onDocumentLoadSuccessを再現しましたが、エラー@ scottie-schneiderが表示されません:(見てみませんか?

https://codesandbox.io/s/little-hooks-bbgek

@wojtekmaj
あなたのPDFには1ページしか含まれていないため、エラー/警告は複数ページのPDFにまだ存在します!

@msgfxegそうではないと思います(このリポジトリは影響を受けません)が、メモ化せずにファイルオブジェクトを使用すると、説明されている問題が発生する可能性があります。

このページは役に立ちましたか?
0 / 5 - 0 評価