I have modal which, when opened, makes an Axios get request and returns a QR Code, but I'm trying to cache the QR Code, so when the modal is reopened, the QR Code doesn't need to be re-requested.
I've tried something like:
const url = window.location.href;
const qrc = useMemo(async () => {
return await getQRCode(url).then((res) => {
return res.data
});
}, [url]);
Then in my jsx:
{qrc ? <img src={qrc} alt="qr code" /> : <LoadingDisplay />}
But of course, qrc
is still a promise. I'm thinking my syntax is just incorrect, but I couldn't figure it out.
edit:
I've used useEffect with useState, which works, but still re-calls the request every time the modal is re-rendered.
Something like
const [qrc, setQrc] = useState<string>("");
const url = window.location.href;
useEffect(() => {
getQRCode(url).then((res) => {
setQrc(res.data);
});
}, [url]);
The modal is opened and closed with a button click calling setShowModal(!showModal)
with the jsx: {showModal && <Modal />}
CodePudding user response:
You might want to make the call from a useEffect
to get the image source, and store the <img>
in a memo.
See: https://codesandbox.io/s/react-qr-code-generator-kjkk9e?file=/src/QRCode.jsx
import { useEffect, useMemo, useState } from "react";
const apiBaseUrl = "https://api.qrserver.com/v1";
const getQRCode = (url, size) =>
fetch(`${apiBaseUrl}/create-qr-code/?size=${size}x${size}&data=${url}`)
.then((res) => res.blob())
.then((blob) => URL.createObjectURL(blob));
const QRCode = (props) => {
const { url, size } = props;
const [src, setSrc] = useState(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
setLoading(true);
getQRCode(url, size)
.then(setSrc)
.finally(() => setLoading(false));
}, [size, url]);
const QRCodeImage = useMemo(() => <img src={src} alt={url} />, [src, url]);
return <>{loading ? <span>Loading...</span> : QRCodeImage}</>;
};
export default QRCode;