始める前に-チェックリスト
説明
次のコンポーネントでは、次の警告が表示されます。
警告:マウントされていないコンポーネントでReact状態の更新を実行することはできません。
再現する手順
これは問題のあるコンポーネントです。
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にアップグレードする前は完全に機能していました。
環境
4.0.2
16.8.1
4.29.3
こんにちは@Kerumen 、
これを試して:
onDocumentLoad = (document) => {
const { numPages } = document;
this.setState({
numPages,
});
};
こちらの例をご覧ください
@Kerumenあなたはそれを機能させましたか?
@ Maxhou00
バンドルから直接ファイルをロードする場合は正常に機能します。 しかし、URLからPDFをロードすると、同じ問題が発生します。
私はアプローチが言及しようとした、ここでそれがロードを続けている上記とネットワークのコールを保つのと同じ問題に直面します。
「警告:マウントされていないコンポーネントでReact状態の更新を実行できません。これは動作しませんが、アプリケーションのメモリリークを示しています。修正するには、componentWillUnmountメソッドのすべてのサブスクリプションと非同期タスクをキャンセルします。
PageInternal内(Context.Consumerによって作成)
ページ内(Test.js:30)」
@qaisershehzadおそらく、すべてのレンダリングで新しいfile
オブジェクトを定義していますか? #308を参照
@wojtekmaj私はこれをやっています:
@wojtekmaj私はこのようにすることでそれを機能させることができます:
また、同じ「マウントされていないコンポーネントの状態更新に反応する」というメッセージが表示されました。 ただし、これは、react-pdfで複数ページのPDFを開いていて、最初のページが読み込まれる前に1つのページから別のページに移動していたときに発生したようです。
私の「修正」は、ページの読み込み時に「onRenderSuccess」イベントが発生するまで、すべてのコントロールを無効にすることでした。 新しいページを読み込もうとします。すべてのコントロールを無効にし、「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);
}
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が表示されません:(見てみませんか?
こんにちは、
同じ問題が発生していますが、Reduxからロードしているバッファーを使用すると、ループに入ります。 これは、ドキュメントの読み込みが成功したときに状態を更新するたびに発生します。
うーん、onDocumentLoadSuccessを再現しましたが、エラー@ scottie-schneiderが表示されません:(見てみませんか?
@wojtekmaj
あなたのPDFには1ページしか含まれていないため、エラー/警告は複数ページのPDFにまだ存在します!
@msgfxegそうではないと思います(このリポジトリは影響を受けません)が、メモ化せずにファイルオブジェクトを使用すると、説明されている問題が発生する可能性があります。
最も参考になるコメント
next.jsプロジェクトでこのライブラリを使用しているときに、この問題が発生しました。
私の理解では、エラーは再レンダリング中に発生します-私の場合、
onLoadSuccess
が呼び出されてnumberOfPages
が更新されたときです。私の現在の解決策は、
useMemo
を使用してファイルオブジェクトをメモ化することです。 これを行うと、エラーは完全に消えます。props.fileSrc
が必要な場合。お役に立てれば。