skip to Main Content

I know what is wrong but don’t know how to correct this. How can I pass updated object to handler instead of inside onDrop function? I’ve looked for solution but I’m using useCallback function and I got error on every solution.

function PortfolioDropzone(params) {
  const [fileList, setFileList] = useState([]);
  const onDrop = useCallback((newFiles) => {
    if (newFiles?.length) {
      setFileList((previousFileList) => [
        ...previousFileList,
        ...newFiles.map((file) =>
          Object.assign(file, { preview: URL.createObjectURL(file) })
        ),
      ]);
      params.uploadHandler(fileList); // This is not working because of async of setState
    }
  }, []);
   
  const { getRootProps, getInputProps, isDragActive } = useDropzone({
    onDrop,
    accept: { "image/*": [] },
    maxSize: 1024 * 10000,
  });

  return (
    <div className="mt-4 mb-4 border rounded p-3">
      <div {...getRootProps({ className: params.className })}>
        <input {...getInputProps()} />
        {isDragActive ? (
          <p className="m-0">Drop file ...</p>
        ) : (
          <p className="m-0">
            Drop file or click to choose file ...
          </p>
        )}
      </div>
      // some code for displaying loaded files and deleting them
    </div>
  );
}

export default PortfolioDropzone;

2

Answers


  1. You can set up an effect to watch for changes in the fileList state and call params.uploadHandler when it changes.

    function PortfolioDropzone(params) {
      const [fileList, setFileList] = useState([]);
    
      useEffect(() => {
        if (fileList.length > 0) {
          params.uploadHandler(fileList);
        }
      }, [fileList, params.uploadHandler]);
    
      const onDrop = useCallback((newFiles) => {
        if (newFiles?.length) {
          setFileList((previousFileList) => [
            ...previousFileList,
            ...newFiles.map((file) =>
              Object.assign(file, { preview: URL.createObjectURL(file) })
            ),
          ]);
        }
      }, []);
    
      // Rest of your code...
    
      return (
        <div className="mt-4 mb-4 border rounded p-3">
          {/* ... */}
        </div>
      );
    }
    
    export default PortfolioDropzone;
    
    Login or Signup to reply.
  2. The issue you’re facing is because you are trying to pass the fileList state to params.uploadHandler(fileList) immediately after updating it within the onDrop callback. The problem is that the setFileList function is asynchronous, so the fileList may not be updated by the time you try to pass it to uploadHandler. To solve this issue, you can either use the updated fileList directly within the onDrop callback or use the useEffect hook to call params.uploadHandler after the state has been updated. I’ll provide an example of using the useEffect approach

    import React, { useState, useCallback, useEffect } from 'react';
    import { useDropzone } from 'react-dropzone';
    
    function PortfolioDropzone(params) {
      const [fileList, setFileList] = useState([]);
      const onDrop = useCallback((newFiles) => {
        if (newFiles?.length) {
          const updatedFileList = [
            ...fileList,
            ...newFiles.map((file) =>
              Object.assign(file, { preview: URL.createObjectURL(file) })
            ),
          ];
          setFileList(updatedFileList);
        }
      }, [fileList]);
    
      useEffect(() => {
        // This will be called whenever fileList changes
        params.uploadHandler(fileList);
      }, [fileList, params.uploadHandler]);
    
      const { getRootProps, getInputProps, isDragActive } = useDropzone({
        onDrop,
        accept: { "image/*": [] },
        maxSize: 1024 * 10000,
      });
    
      return (
        <div className="mt-4 mb-4 border rounded p-3">
          <div {...getRootProps({ className: params.className })}>
            <input {...getInputProps()} />
            {isDragActive ? (
              <p className="m-0">Drop file ...</p>
            ) : (
              <p className="m-0">
                Drop file or click to choose file ...
              </p>
            )}
          </div>
          {/* some code for displaying loaded files and deleting them */}
        </div>
      );
    }
    
    export default PortfolioDropzone;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search