How to solve async setState poblem?

I’ve code below. console.log from useEffect shows current "files" value, but console.log from handleInputChange function always show previous value. I understand this is because of async setState behavour, but I don’t understand how to make it work.

   import React, { useState, useEffect } from 'react';
    import Button from '../Button/Button';
    
    function Card({ accept }) {
      let [uploadDisabled, setUploadDisabled] = useState(true);
      let [multiple, setMultiple] = useState(true);
      let [files, setFiles] = useState([]);
    
      function handleOpenClick() {
        const inputEl = document.getElementById('file');
        inputEl.click();
      }
    
      useEffect(() => {
        console.log(files);
      });
    
      function handleInputChange(event) {
        event.preventDefault();
    
        if (!event.target.files) return;
    
        setUploadDisabled(false);
        setFiles(Array.from(event.target.files));
        console.log(files)
    
        files.forEach((file) => {
          const reader = new FileReader();
    
          reader.onload = (event) => {
            const src = event.target.result;
            const alt = file.name;
          };
        });
      }
    
      return (
        <div className='card'>
          <input
            type='file'
            id='file'
            multiple={multiple}
            onChange={(event) => handleInputChange(event)}
            accept={accept.join(',')}
          />
          <Button value='Open' className='btn' handleClick={handleOpenClick} />
          <Button value='Upload' className='btn primary' disabled={uploadDisabled} />
        </div>
      );
    }
    
    export default Card;

>Solution :

Why you just use files from event params?

setFiles(Array.from(event.target.files));

you did it shown in the above code so you expect files to be equals to event.target.files and handle it in future with forEach

files.forEach((file) => {
  const reader = new FileReader();

   reader.onload = (event) => {
     const src = event.target.result;
     const alt = file.name;
   };
});

So you can do

const files = Array.from(event.target.files);

files.forEach((file) => {
  const reader = new FileReader();
    
  reader.onload = (event) => {
    const src = event.target.result;
    const alt = file.name;
  };
});

setFiles(files);

Another point is that you need array dependency in useEffect

useEffect(() => {
  console.log(files);
}, [files]);

Sorry for my bad english. I hope it solves.

Leave a Reply