запускать функцию перед генерацией pdf в react-pdf плагине react

Я использую два плагина 1react-pdf для генерации pdf и плагин html-to-image для конвертации html в изображение. Но проблема в том, что функция конвертации срабатывает только после создания pdf. Вот эта функция:

const downloadImage = async () => {
  return await htmlToImage.toPng(testEl.current, {
    cacheBust: false,
  })
}

В этой функции я возвращаю URL, который помещаю в компонент <Image />. Например:

<Image src={downloadImage} cache={false} />

Может быть, поместить функцию в useEffect? Пожалуйста, помогите мне с этим. Вот полный код:

import {PDFDownloadLink, Page, Text, View, Document,Image} from "@react-pdf/renderer";
import * as htmlToImage from "html-to-image";

export function CustomComponent() {
  const testEl = useRef();

  const downloadImage = async () => {
    return await htmlToImage.toPng(testEl.current, {
      cacheBust: false,
    });
  };

  const MyDoc = () => (
    <Document>
      <Page>
        <View>
          <Image src={downloadImage} cache={false} />
        </View>
      </Page>
    </Document>
  );

  return (
    <>
      <div ref={testEl} className="test">
        Text
      </div>
      <PDFDownloadLink document={<MyDoc />} fileName="print-test.pdf">
        {({ blob, url, loading, error }) =>
          loading ? "Loading document..." : "Download now!"
        }
      </PDFDownloadLink>
    </>
  );
}

EDIT

const downloadImage = () => {
  return htmlToImage.toPng(testEl.current, {
    cacheBust: false,
  });
};

const MyDoc = () => {
  return (
    <Document>
      <Page>
        <View>
          <Image src={downloadImage} cache={false} />
        </View>
      </Page>
    </Document>
  );
};

const asyncF = async () => {
  await downloadImage();
  await MyDoc();
};

useEffect(() => {
  asyncF();
});

EDIT 2

import React, { useState, useEffect, useRef, Fragment } from "react";
import { usePDF, Page, Text, View, Document, Image } from "@react-pdf/renderer";
import * as htmlToImage from "html-to-image";

export function CustomComponent({}) {

  const downloadImage = async () => {
    return await htmlToImage.toPng(
      document.querySelector(".test"),
      { cacheBust: false }
    );
  };

  const myPdfDocument = (
    <Document>
      <Page>
        <View>
          <Image src={downloadImage} cache={false} />
        </View>
      </Page>
    </Document>
  );

  function triggerDownload(url) {
    const a = document.createElement("a");
    a.href = url;
    a.download = "test.pdf";
    a.click();
  }

  const [pdfInstance, updatePdfInstance] = usePDF({});
  const [isDownloading, setIsDownloading] = useState(false);

  function initiateDownload() {
    setIsDownloading(true);
    updatePdfInstance(myPdfDocument);
  }

  useEffect(() => {
    if (isDownloading && pdfInstance.url) {
      triggerDownload(pdfInstance.url);
      setIsDownloading(false);
    }
  }, [isDownloading, pdfInstance.url]);

  return (
    <>
      <div className="test">Text</div>
      <button onClick={initiateDownload} disabled={isDownloading}>
        {isDownloading ? "Loading..." : "Download PDF"}
      </button>
    </>
  )
}

Ответы (1 шт):

Автор решения: SwaD

Условно...

Попробуйте сделать так:

const MyDoc = (image) => {
  return (
    <Document>
      <Page>
        <View>
          <Image src={image} cache={false} />
        </View>
      </Page>
    </Document>
  );
};

const asyncF = async () => {
  const img = await downloadImage();
  await MyDoc(img);
};

Надо только поэкспериментировать с тем, передавать ли все вернувшееся из функции downloadImage или только .url


const myPdfDocument = (img) => (
    <Document>
      <Page>
        <View>
          <Image src={img} cache={false} />
        </View>
      </Page>
    </Document>
  );

async function initiateDownload() {
  //setIsDownloading(true);
  const img = await downloadImage(); // берем текущее значение
  const newPDF = myPdfDocument(img); // Создаем пдф
  triggerDownload(newPDF.url); // генерим ссылку
  // тут можно вызвать какой нибудь сеттер для обновления компонента
}
→ Ссылка