skip to Main Content

I would like to run the following code to have the file selector input a file and manage the input file as a state in the file. But it produces output as described in the comments. I do not know the cause. How should I fix the problem?

const [file, setFile] = useState<File | null>(null);

const fileSelect = (event: ReactChangeEvent<HTMLInputElement>) => {
  if (event.target.files === null) { return ; }
  const f: File | null = event.target.files[0];
  console.log(typeof(f)); // <- object
  setFile(f);
  console.log(f); // <- null
}

return (
<div className="flex px-1">
<input
  onChange={fileSelect}
  type="file"
/>
</div>
);

2

Answers


  1. This is because when you call setState it doesn’t mutate the state immediately. You can refer to this thread here.
    Why does calling react setState method not mutate the state immediately?

    Login or Signup to reply.
  2. Based on your Typescript data types, it appears you want to save the actual file contents into state, not just the name of the file.

    These lines in your code:

    const f: File | null = event.target.files[0];
    console.log(typeof(f)); // <- object
    setFile(f);
    

    …show an attempt to update state with type File, not type string.

    Saving file contents into state can be achieved with React.useState. File contents can be converted to Base64 and stored in state as strings.

    These demos on JS Fiddle use React.useState and Redux Toolkit. Source code is available on SourceHut: React.useState; Redux Toolkit.

    The demos use the FileReader: readAsDataURL() method to upload files as Data URLs which can be saved as strings (not strictly as File types) in an array using React.useState.

    These functions are the key to saving file content:

    Read the file as a Data URL and update state

    function processFiles( file ) {
        var filereader = new FileReader();
        filereader.onload = function onLoadCallbck( fileEvent ) {
            let dataUrl = fileEvent.target.result;
            let newFile = {
                dataUrl,
                fileName: file.name,
                fileType: file.type
            };
            setFiles( ( prev ) => {
                let list = [ ...prev ];
                let newList = list.concat( newFile );
                return newList;
            } );
        }
    
        filereader.readAsDataURL( file );
    }
    

    Event handler for file upload field

    /**
     * Event listener for the file upload input field.
     */
    function handleFiles( event ) {
        if ( ! event.target.files.length ) {
            listRef.current.innerHTML = "<p>No files selected!</p>";
        } else {
            listRef.current.textContent = "";
            Array.prototype.forEach.call( event.target.files, processFiles );
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search