I try to create a qrcode app with react. After the user submit form with value to create a svg , they can also download it. But i cant make it work , each time it download the same svg.
my download function
const downloadQRCode = (e) => {
e.preventDefault();
let svg = qrRef.current.querySelector("svg");
let svgXML = new XMLSerializer().serializeToString(svg);
let dataUrl = "data:image/svg," encodeURIComponent(svgXML);
let anchor = document.createElement("a");
anchor.href = dataUrl;
anchor.download = `qr-code.svg`;
document.body.appendChild(anchor);
anchor.click();
document.body.removeChild(anchor);
};
Here i use map to render qrcode component and a button to download the svg
qrcode.map((item) => {
return (
<li ref={qrRef}>
<QRCode
className="qrcode"
size={item.size}
value={item.value}
bgColor={item.bgcolor}
fgColor={item.fgcolor}
level="L"
renderAs="svg">
</QRCode>
<form onSubmit={downloadQRCode}>
<button type="submit">Download</button>
</form>
</li>
)
}
CodePudding user response:
It looks like you are using a single React ref for all the qrcode you are mapping. I suggest using an array of React refs and passing this to the button's onClick handler.
const qrcodeRefs = React.useRef([]);
qrcodeRefs.current = qrcode.map((_, i) => qrcodeRefs.current[i] ?? createRef());
...
const downloadQRCode = (qrRef) => e => {
const svg = qrRef.current.querySelector("svg");
const svgXML = new XMLSerializer().serializeToString(svg);
const dataUrl = "data:image/svg," encodeURIComponent(svgXML);
const anchor = document.createElement("a");
anchor.href = dataUrl;
anchor.download = `qr-code.svg`;
document.body.appendChild(anchor);
anchor.click();
document.body.removeChild(anchor);
};
...
qrcode.map((item, index) => {
return (
<li ref={qrcodeRefs.current[i]}>
<QRCode
className="qrcode"
size={item.size}
value={item.value}
bgColor={item.bgcolor}
fgColor={item.fgcolor}
level="L"
renderAs="svg"
/>
<button type="button" onClick={downloadQRCode(qrcodeRefs.current[i])}>
Download
</button>
</li>
)
}
CodePudding user response:
if you use ref in a loop, it will hold the last value.
you do not need a ref, replace
let svg = qrRef.current.querySelector("svg");
with
// e.target.parentNode is the li dom
let svg = e.target.parentNode.querySelector("svg");
