Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to prevent the white 'flash' while changing slides? #418

Closed
3 tasks done
igoroctaviano opened this issue Jun 25, 2019 · 14 comments
Closed
3 tasks done

How to prevent the white 'flash' while changing slides? #418

igoroctaviano opened this issue Jun 25, 2019 · 14 comments
Assignees
Labels
question Further information is requested

Comments

@igoroctaviano
Copy link

igoroctaviano commented Jun 25, 2019

  • I have read documentation in README
  • I have checked sample and test suites to see real life basic implementation
  • I have checked if this question is not already asked

I'd like to display multiple pages of my PDF and move through them without white flash (dark background).

I tried changing the CSS.

Environment

  • React-PDF version: 4.0.5
  • React version: 16.8.6
@wojtekmaj wojtekmaj self-assigned this Jun 26, 2019
@wojtekmaj wojtekmaj added the question Further information is requested label Jun 26, 2019
@wojtekmaj
Copy link
Owner

You could render the new Page hidden using CSS, wait for onRenderSuccess on it, and only then remove the old page and show the new one.

@igoroctaviano
Copy link
Author

Thank you.

@AkshayHere
Copy link

AkshayHere commented Jul 25, 2019

Can you please tell me how to do this ?

@igoroctaviano
Copy link
Author

igoroctaviano commented Jul 25, 2019

Can you please tell me how to do this?

So, in their Page component I have added the onRenderSuccess prop that sets a loading boolean state that I have created in my PDF component that uses their components:
onRenderSuccess={() => { this.setState({ loading: false }); }}
*The loading boolean default value is true.

Also, I added my custom default class to their page component:
className="react-pdf__Page"
Which basically sets the Page component to display none until the loading boolean is false.

Then.. on their Document component I have added the native className prop:
className={`pdf-document-viewer ${ !this.state.loading ? 'pdf-loaded' : '' }`}
...which adds my custom css based on the loading state I created.

My custom CSS to remove the white flash:

.react-pdf__Page {
  display: none;
}

 .pdf-loaded .react-pdf__Page {
  display: inline-block;
}

Summary: Start the Page component as display none until the onRenderSuccess is executed and sets the loading to false, then the pdf-loaded class is added in the page component which sets the display to inline-block, avoiding the whole flash thing.

@saadq
Copy link
Contributor

saadq commented Jun 30, 2020

Kinda similar so I wanted to avoid opening a new issue, is there a way to prevent the white flash when changing the file that is passed to the <Document> component (which triggers the loading state and results in a white flash)? Right now I have a website that creates a PDF on the backend when you press the Make button and then sends that to the client which then updates the file attribute that is passed to <Document> with that new PDF.

I'm not sure what would be the best solution to handle this, maybe a similar solution to switching pages (keeping the old document rendered until the new one has finished loading) but im not sure if that's possible.

@AkshayHere
Copy link

@saadq i follow the method mentioned for generating pdf where u generate a pdf file in backend server and render it my ui side. Actually if u notice u will get the white flash for the initial rendering of each pages & subsequent changes wont give u the flicker.

I dont think there is a workable solution on this at the moment

@casulit
Copy link

casulit commented Jul 18, 2020

@igoroctaviano can you share the codes regarding this issue? I follow your instruction still getting the flash when slide changes.

@wojtekmaj
Copy link
Owner

wojtekmaj commented Jul 20, 2020

The best way to avoid flashing is to keep the previous page rendered on top of current page, until the next one is fully rendered:

CodeSandbox

function Test() {
  const [numPages, setNumPages] = useState(null);
  const [pageNumber, setPageNumber] = useState(1);
  const [renderedPageNumber, setRenderedPageNumber] = useState(null);

  function onDocumentLoadSuccess({ numPages }) {
    setNumPages(numPages);
  }

  function changePage(offset) {
    setPageNumber(prevPageNumber => prevPageNumber + offset);
  }

  function previousPage() {
    changePage(-1);
  }

  function nextPage() {
    changePage(1);
  }

  const isLoading = renderedPageNumber !== pageNumber;

  return (
    <>
      <Document file={samplePDF} onLoadSuccess={onDocumentLoadSuccess}>
        {isLoading && renderedPageNumber ? (
          <Page 
            {/** 
              * IMPORTANT: Keys are necessary so that React will know which Page component
              * instances to use.
              * Without keys, on page number update, React would replace the page number
              * in 1st and 2nd page components. This may cause previously rendered page
              * to render again, thus causing a flash.
              * With keys, React, will add prevPage className to previously rendered page, 
              * and mount new Page component instance for the new page.
              */}
            key={renderedPageNumber}
            className="prevPage" 
            pageNumber={renderedPageNumber} 
            width={400} 
          />
        ) : null}
        <Page
          key={pageNumber}
          pageNumber={pageNumber}
          onRenderSuccess={() => setRenderedPageNumber(pageNumber)}
          width={400}
        />
      </Document>
      <div>
        <p>
          Page {pageNumber || (numPages ? 1 : "--")} of {numPages || "--"}
        </p>
        <button type="button" disabled={pageNumber <= 1} onClick={previousPage}>
          Previous
        </button>
        <button
          type="button"
          disabled={pageNumber >= numPages}
          onClick={nextPage}
        >
          Next
        </button>
      </div>
    </>
  );
}
.react-pdf__Page.prevPage {
  position: absolute !important;
  z-index: 1;
}

@casulit
Copy link

casulit commented Jul 20, 2020

@wojtekmaj awesome! thank you.

@unclebay143
Copy link

Still works! Thanks @wojtekmaj

@varunKT001
Copy link

varunKT001 commented Mar 16, 2023

@wojtekmaj

Instead of positioning the prevPage absolutely, hiding the page while loading works better in my case.

{isLoading && renderedPageNumber ? (
  <Page
    key={renderedPageNumber}
    pageNumber={renderedPageNumber}
  />
) : null}
<Page
  className={`${isLoading ? 'loadingPage' : ''}`}
  key={pageNumber}
  pageNumber={pageNumber}
  onRenderSuccess={() => setRenderedPageNumber(pageNumber)}
/>
.react-pdf__Page.loadingPage {
  display: none;
}

BTW, awesome library. I'm loving it!

@Againyunn

This comment has been minimized.

@BeaComp

This comment has been minimized.

@tducloc
Copy link

tducloc commented Jun 7, 2024

The best way to avoid flashing is to keep the previous page rendered on top of current page, until the next one is fully rendered:

CodeSandbox

function Test() {
  const [numPages, setNumPages] = useState(null);
  const [pageNumber, setPageNumber] = useState(1);
  const [renderedPageNumber, setRenderedPageNumber] = useState(null);

  function onDocumentLoadSuccess({ numPages }) {
    setNumPages(numPages);
  }

  function changePage(offset) {
    setPageNumber(prevPageNumber => prevPageNumber + offset);
  }

  function previousPage() {
    changePage(-1);
  }

  function nextPage() {
    changePage(1);
  }

  const isLoading = renderedPageNumber !== pageNumber;

  return (
    <>
      <Document file={samplePDF} onLoadSuccess={onDocumentLoadSuccess}>
        {isLoading && renderedPageNumber ? (
          <Page 
            {/** 
              * IMPORTANT: Keys are necessary so that React will know which Page component
              * instances to use.
              * Without keys, on page number update, React would replace the page number
              * in 1st and 2nd page components. This may cause previously rendered page
              * to render again, thus causing a flash.
              * With keys, React, will add prevPage className to previously rendered page, 
              * and mount new Page component instance for the new page.
              */}
            key={renderedPageNumber}
            className="prevPage" 
            pageNumber={renderedPageNumber} 
            width={400} 
          />
        ) : null}
        <Page
          key={pageNumber}
          pageNumber={pageNumber}
          onRenderSuccess={() => setRenderedPageNumber(pageNumber)}
          width={400}
        />
      </Document>
      <div>
        <p>
          Page {pageNumber || (numPages ? 1 : "--")} of {numPages || "--"}
        </p>
        <button type="button" disabled={pageNumber <= 1} onClick={previousPage}>
          Previous
        </button>
        <button
          type="button"
          disabled={pageNumber >= numPages}
          onClick={nextPage}
        >
          Next
        </button>
      </div>
    </>
  );
}
.react-pdf__Page.prevPage {
  position: absolute !important;
  z-index: 1;
}

I have tried this solution but it will not work if you render more than one page. The second page will still be flicked. This is the sandbox that I re-produce bug

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

10 participants