Download JSON formed in Browser
In my todo app I stored all data in a JSON in LocalStorage.
To move from my old domain to a new one I needed export/import functionality.
To do the export I used JSON.stringify
, btoa
and an anchor tag with href pointing to a Data URI scheme:
function ExportTodos({ todos = [] }) {
const todos64 = [todos]
.map((val) => JSON.stringify(val)) // js object to string
.map(btoa) // string to base64
[0];
return (
<a href={`data:application/json;base64,${todos64}`}>
Export
</a>
);
}
But the btoa
function crushed:
btoa('Привет, world!')
// Uncaught DOMException: String contains an invalid character
I started to look for the reason. Turns out btoa
has a unicode problem.
I found some solutions:
- using btoa alternatives (mdn, npm package)
- using Blob
Using Blob there were 2 ways to form a download URL:
- using URL.createObjectURL()
- using FileReader.readAsDataURL
The first method was simpler so I used it. But there was a potential issue with memory, but simple useEffect's cleanup function solved it.
function ExportTodos({ todos = [] }) {
const [downloadURL, setDownloadURL] = useState('');
useEffect(() => {
const blob = new Blob(
[JSON.stringify(todos)],
{ type: 'application/json' }
);
const downloadURL = URL.createObjectURL(blob);
setDownloadURL(downloadURL);
return () => {
URL.revokeObjectURL(downloadURL)
}
}, [todos]);
return (
<a
download={`todos.json`}
href={downloadURL}
>
Export
</a>
);
}
Full ExportTodos component file is here.