-2

I'm trying to fetch data with axios, I use console.log and it's seem worked fine. But when I try to set it to my state, it's return an empty array. I'm tried to searching my problem but have no luck. Any idea?

import React, { useState } from 'react';
import axios from 'axios';
import Error from '../components/Error';

export const PhotoContext = React.createContext();

const apiKey = '636e1481b4f3c446d26b8eb6ebfe7127';

const PhotoContextProvider = (props) => {
  const [images, setImages] = useState([]);
  const [loading, setLoading] = useState<boolean>(false);
  const runSearch = (query) => {
    axios
      .get(
        `https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=${apiKey}&tags=${query}&per_page=24&format=json&nojsoncallback=1`
      )
      .then((response) => {
        setImages(response.data.photos.photo);
        setLoading(false);
        console.log(images); //return an empty array
        console.log(response.data.photos.photo); // return an object as it should be
      })
      .catch((err) => {
        return <Error />;
      });
  };
  return (
    <PhotoContext.Provider value={{ images, loading, runSearch }}>
      {props.children}
    </PhotoContext.Provider>
  );
};

export default PhotoContextProvider;

Here's my full code on stackblitz: https://stackblitz.com/edit/react-ts-hhqiwr?file=context%2FPhotoContext.tsx

baba mama
  • 33
  • 6
  • What purpose do your `console.log()` lines serve? Did you need those particular pieces of data logged for some reason? Was the rest of your app not working as expected? – Phil Mar 21 '22 at 06:58

1 Answers1

0

The problem is, setting of state is async, if you console.log images after using setImages, it will return the old value.

The correct way is to use useEffect to monitor changes.

useEffect(() => {

  console.log('images', images) //new value will be reflected

},[images])

I've checked your codesandbox and it is setting the state correctly for response.data.photos.photo

Someone Special
  • 12,479
  • 7
  • 45
  • 76
  • Setting state is in fact synchronous. What it cannot do is update the state value in an already declared variable until the next render. – Phil Mar 21 '22 at 06:59
  • Partly right @Phil https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous It's not immediate and it's non-blocking, hence it's async – Someone Special Mar 21 '22 at 07:01
  • I'm not sure that applies to the `useState` hook since each of those would be tracked individually. I suppose multiple calls to the same _setter_ may be batched. I just think it's incorrect to say that setting state is asynchronous. It's the render cycle that provides delays between writing a value and being able to read it – Phil Mar 21 '22 at 07:03
  • @babamama Add a conditional check (for undefine values) before you use `setImages` – Someone Special Mar 21 '22 at 07:32