Skip to content

Instantly share code, notes, and snippets.

@jeremy-code
Last active April 20, 2026 02:07
Show Gist options
  • Select an option

  • Save jeremy-code/7c17298a6b25b1104f704c959cd3e00a to your computer and use it in GitHub Desktop.

Select an option

Save jeremy-code/7c17298a6b25b1104f704c959cd3e00a to your computer and use it in GitHub Desktop.
useFileReader.tsx
import { useSyncExternalStore } from "react";
enum ReadyState {
EMPTY,
LOADING,
DONE,
}
const useFileReader = () => {
const fileReader = new FileReader();
// Error may be"AbortError" DOMException
const error = useSyncExternalStore(
(onStoreChange) => {
fileReader.addEventListener("error", onStoreChange);
fileReader.addEventListener("abort", onStoreChange);
return () => {
fileReader.removeEventListener("error", onStoreChange);
fileReader.removeEventListener("abort", onStoreChange);
};
},
() => fileReader.error,
);
const readyState = useSyncExternalStore(
(onStoreChange) => {
fileReader.addEventListener("loadend", onStoreChange);
return () => fileReader.removeEventListener("loadend", onStoreChange);
},
(): ReadyState => fileReader.readyState,
);
const result = useSyncExternalStore(
(onStoreChange) => {
fileReader.addEventListener("load", onStoreChange);
return () => fileReader.removeEventListener("load", onStoreChange);
},
() => fileReader.result,
);
return {
fileReader,
error,
readyState,
result,
};
};
export { useFileReader, ReadyState };
@jeremy-code
Copy link
Copy Markdown
Author

How to use:

  const { fileReader, error, readyState, result } = useFileReader();

  if (readyState === ReadyState.EMPTY) {
    fileReader.readAsDataURL(file);
  }

  if (result !== null) {
    // do whatever
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment