diff --git a/__mocks__/_failing_page.js b/__mocks__/_failing_page.js index 790168776..5c5ecb121 100644 --- a/__mocks__/_failing_page.js +++ b/__mocks__/_failing_page.js @@ -1,4 +1,7 @@ export default { + cleanup: () => { + // Intentionally empty + }, commonObjs: { get: () => { // Intentionally empty diff --git a/src/Outline.jsx b/src/Outline.jsx index e0a7065c7..1524e7805 100644 --- a/src/Outline.jsx +++ b/src/Outline.jsx @@ -1,4 +1,4 @@ -import React, { PureComponent } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import PropTypes from 'prop-types'; import makeCancellable from 'make-cancellable-promise'; import makeEventProps from 'make-event-props'; @@ -15,101 +15,93 @@ import { cancelRunningTask } from './shared/utils'; import { eventProps, isClassName, isPdf, isRef } from './shared/propTypes'; -export class OutlineInternal extends PureComponent { - state = { - outline: null, - }; +export function OutlineInternal({ + className, + inputRef, + onItemClick: onItemClickProps, + onLoadError: onLoadErrorProps, + onLoadSuccess: onLoadSuccessProps, + pdf, + ...otherProps +}) { + const [outline, setOutline] = useState(null); - componentDidMount() { - const { pdf } = this.props; + invariant(pdf, 'Attempted to load an outline, but no document was specified.'); - invariant(pdf, 'Attempted to load an outline, but no document was specified.'); + /** + * Called when an outline is read successfully + */ + const onLoadSuccess = useCallback( + (nextOutline) => { + if (onLoadSuccessProps) { + onLoadSuccessProps(nextOutline); + } + }, + [onLoadSuccessProps], + ); - this.loadOutline(); - } + /** + * Called when an outline failed to read successfully + */ + const onLoadError = useCallback( + (error) => { + setOutline(false); - componentDidUpdate(prevProps) { - const { pdf } = this.props; + warning(false, error); + + if (onLoadErrorProps) { + onLoadErrorProps(error); + } + }, + [onLoadErrorProps], + ); - if (prevProps.pdf && pdf !== prevProps.pdf) { - this.loadOutline(); + function onItemClick({ dest, pageIndex, pageNumber }) { + if (onItemClickProps) { + onItemClickProps({ + dest, + pageIndex, + pageNumber, + }); } } - componentWillUnmount() { - cancelRunningTask(this.runningTask); + function resetOutline() { + setOutline(null); } - loadOutline = () => { - const { pdf } = this.props; - - this.setState((prevState) => { - if (!prevState.outline) { - return null; - } - return { outline: null }; - }); + useEffect(resetOutline, [pdf]); + function loadOutline() { const cancellable = makeCancellable(pdf.getOutline()); - this.runningTask = cancellable; + const runningTask = cancellable; cancellable.promise - .then((outline) => { - this.setState({ outline }, this.onLoadSuccess); + .then((nextOutline) => { + setOutline(nextOutline); + onLoadSuccess(nextOutline); }) - .catch((error) => { - this.onLoadError(error); - }); - }; - - get childContext() { - return { - onClick: this.onItemClick, - }; - } + .catch(onLoadError); - get eventProps() { - return makeEventProps(this.props, () => this.state.outline); + return () => cancelRunningTask(runningTask); } - /** - * Called when an outline is read successfully - */ - onLoadSuccess = () => { - const { onLoadSuccess } = this.props; - const { outline } = this.state; - - if (onLoadSuccess) onLoadSuccess(outline); - }; - - /** - * Called when an outline failed to read successfully - */ - onLoadError = (error) => { - this.setState({ outline: false }); - - warning(false, error); + useEffect(loadOutline, [onLoadError, onLoadSuccess, pdf]); - const { onLoadError } = this.props; - - if (onLoadError) onLoadError(error); + const childContext = { + onClick: onItemClick, }; - onItemClick = ({ dest, pageIndex, pageNumber }) => { - const { onItemClick } = this.props; - - if (onItemClick) { - onItemClick({ - dest, - pageIndex, - pageNumber, - }); - } - }; + const eventProps = useMemo( + () => makeEventProps(otherProps, () => outline), + [otherProps, outline], + ); - renderOutline() { - const { outline } = this.state; + if (!outline) { + return null; + } + function renderOutline() { return (