0

i am trying to upload a file into a state variable.

function CreateCarouselPost() {
  const [file, setFile] = useState(null);
  
  const handleFileUpload = (e) => {
    setFile(e.target.files[0]); 
    console.log(file); // file is still null 
  }

  return (
    <div className='create-carousel-container'>
      <h2 className='create-carousel-header'>Add Images and Videos</h2>
      <div className='create-carousel-grid'>
        <div className='add-image-video-card grid-item'>
          <input
            className='carousel-file-upload'
            type='file'
            name='content'
            accept='image/*,video/*'
            onChange={handleFileUpload}
          />
        </div>
      </div>
    </div>
  );
}

But i go to know that setState is asynchronous and can take time. So when i console.log file immediately after setFile, file is still null. When i upload another file, it has contents of previous file. So, i tried to wait for it by using Promises but i couldn't get it to work.

import React, { useState, useEffect } from 'react';
import AddIcon from '@material-ui/icons/Add';
import './styles/Carousel.css';

function CreateCarouselPost() {
  const [file, setFile] = useState(null);

  const uploadFile = (file) => {
    return new Promise((resolve) => {
      setFile(file);
      resolve();
    });
  };

  const handleFileUpload = (e) => {
    uploadFile(e.target.files[0]).then(() => {
      console.log('file = ', file);
    });
  };

  return (
    <div className='create-carousel-container'>
      <h2 className='create-carousel-header'>Add Images and Videos</h2>
      <div className='create-carousel-grid'>
        <div className='add-image-video-card grid-item'>
          <input
            className='carousel-file-upload'
            type='file'
            name='content'
            accept='image/*,video/*'
            onChange={handleFileUpload}
          />
        </div>
      </div>
    </div>
  );
}

export default CreateCarouselPost;

As far as my understanding Promise will be resolved after all the code inside is executed and then resolve function is called. So i tried to place it inside Promise and tried to access the file state inside the resolve(). But it turns out that the issue is still same (not getting the latest value). please help to do it in right way.

Sanketh B. K
  • 759
  • 8
  • 22
  • 2
    This problem was answered before. Check out here: https://stackoverflow.com/questions/54069253/usestate-set-method-not-reflecting-change-immediately – BertC Jul 26 '21 at 07:16
  • 2
    This will help: https://stackoverflow.com/questions/56247433/how-to-use-setstate-callback-on-react-hooks – CyberDev Jul 26 '21 at 07:18
  • 1
    What exactly do you actually want to wait for? To log the right file, doing `console.log(e.target.files[0])` in the event handler would suffice, no asynchronous stuff necessary. – Bergi Jul 26 '21 at 07:59
  • @Bergi Yeah i want to send it server using axios after that so. – Sanketh B. K Jul 26 '21 at 08:29
  • @BertC Thank you very much it will solve my issue – Sanketh B. K Jul 26 '21 at 08:30
  • 1
    @SankethB.K There's nothing you need to wait for. Just send the `e.target.files` right from that callback. Do not use the `file` constant. – Bergi Jul 26 '21 at 08:38
  • @Bergi Yeah that would be better. – Sanketh B. K Jul 27 '21 at 09:25

1 Answers1

1

You should use useEffect hook. This will serve as a callback after state is set.

For example:

function CreateCarouselPost() {
  const [file, setFile] = useState(null);
  
  const handleFileUpload = (e) => {
    setFile(e.target.files[0]); 
  }

  useEffect(() => {
    console.log(file); // after file has been added to state
  }, [file]);

  return (
    <div className='create-carousel-container'>
      <h2 className='create-carousel-header'>Add Images and Videos</h2>
      <div className='create-carousel-grid'>
        <div className='add-image-video-card grid-item'>
          <input
            className='carousel-file-upload'
            type='file'
            name='content'
            accept='image/*,video/*'
            onChange={handleFileUpload}
          />
        </div>
      </div>
    </div>
  );
}

Here's the documentation to useEffect: https://reactjs.org/docs/hooks-effect.html

CyberDev
  • 228
  • 1
  • 7