Search code examples
reactjstypescriptfilesetstatereact-functional-component

setState isn't updating immediately


I am working with a react aplication and i'm tryna to update a state and it isnt updating immediately. I looked for it inm internet and found, but the problem is, all this people are using classes componets and i'm using functional componets. they are talking about callbacks in setState function, but i tried it in my code, and didn't work!!

Heres my code:

async function handleSelectImage(event: ChangeEvent <HTMLInputElement>) {
    if (!event.target.files) {
      return;
    }
    const selectedImages = Array.from(event.target.files);
    selectedImages.map((image) => {
      if (!(image.type === 'image/png' || image.type === 'image/jpg' || image.type === 'image/jpeg')) {
        const imageIndex = selectedImages.indexOf(image);
        selectedImages.splice(imageIndex, 1);
        alert('Só são aceitos arquivos jpeg, jpg e png.');
      }
    });

    try {
      setImages(images.concat(selectedImages));
    } catch (err) {
      console.error(err);
    }
    console.log(images);


Hope you can help me!!!! THX!!! :)


Solution

  • State can't be read in functional components in React because it's an async operation.

    So, it's not that your state ISN'T updating, but that your console.log(images) function is called and read before your async function that updates state returns.

    Okay... so what to do about that?

    Two options: 1. Pass state into another component and read it there. This one is preferred, imo, because you can separate your stateful components from your "dumb" components.

    So in your component above, you can pass images as a prop to a child component:

    Inside the ImageDisplay, get the images state from props.

    2. Wait for the async function to update inside your component. If you really want to read state inside your functional component, you have to wait for the async function to return. To do this, I think the easiest way is to set a "waiting" state, like so.

    const [isLoading, setLoading] = useState(true);
    
    /// rest of your call and your async function 
    ///try block: 
    try {
          setImages(images.concat(selectedImages));
          setLoading(false);
        } catch (err) {
          console.error(err);
        }
    
    if(setLoading) {
      console.log("The images haven't loaded yet");
    } else {
      console.log(images)
    }
    

    Basically, you're giving the component a conditional to wait for the image state to change. When that conditional is no longer true, the images will be ready to be displayed. (You can do this with rendering data on the frontend, too, not just the console!)

    Good luck.