Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

147
Views
React Dropzone - async function in onDrop callback doesn't update state

I'm trying to use react-dropzone onDrop with useCallback function to update the array of files dropped onto the area and trigger the upload. My code looks like this:

const [files, setFiles] = useState([]);

...

const onDrop = useCallback((acceptedFiles) => {
  setFiles(acceptedFiles);
  handleFileUpload();
}, []);

const {
  getRootProps,
  getInputProps,
  isDragActive,
} = useDropzone({ onDrop });

handleFileUpload is an asynchronous function, which uses Fetch API. When I try to log the files array inside this method, it appears to be empty, even though I updated the state before running this function.

const handleFileUpload = async () => {
  console.log(files); // <- returns empty array
}

I also tried to set different variables to indicate if the upload has started, etc. but changing the values within this method doesn't update the state of my component at all. Is it even possible to use an async function in a callback like this? Should I trigger the file upload somewhere else? I feel like I don't quite understand the concept here.

about 4 years ago · Juan Pablo Isaza
1 answers
Answer question

0

Your state will not update until after your code exits and/or relinquishes control. i.e. after you call setFiles() the files variable will still be STALE until the code returns to the event loop.

Just pass the accepted files into the function.

const onDrop = useCallback((acceptedFiles) => {
  setFiles(acceptedFiles); // <-- that won't update right away
  handleFileUpload(acceptedFiles);
}, []);

UPDATE

Here are snippets from one of my projects. I just stuff the dropped file into state, as you do. That causes the component to re-render, and when it does, I catch the updated file state in a hook, async parse the file, and return the data - which is then consumed by the component. The component shows UI states - importing if fileToImport is set and dataToImport is not yet available, etc...

// MyComponent.tsx
const MyComponent = () => {
  const [fileToImport, setFileToImport] = useState<File | undefined>()
  const [dataToImport, dataToImportError] = useReadFileData(fileToImport)

  const onDrop = useCallback(acceptedFiles => {
    setFileToImport(acceptedFiles[0])
  }, [])


//useREadFileData.ts hook
import { useEffect, useState } from 'react'

const useReadFileData = (file: File | undefined): [any[], string | undefined] => {
  const [rows, setRows] = useState<unknown[]>([])
  const [error, setError] = useState<string>()

  useEffect(() => {
    async function parseFile(file: File) {
      try {
        // snip
        setRows(rows)
      } catch (error: any) {
        if (typeof error === "object") {
          setError(error?.message ?? "Error parsing file")
        }
      }
    }
    // only if we have a file to parse
    if (file) {
      parseFile(file)
    }
  }, [file, setError, setRows])

  return [rows, error]
}

export default useReadFileData
about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!