0

My code is not long or complicated at all. It's simple. so please read! (Im using react + next.js)

  1. In the root file, app.js, I have useEffect to fetch photo data. This data array will be used in a page component so I pass it down from app.js via <Component.../>
function MyApp({ Component, pageProps }) {
  const [photoData, setPhotoData] = useState([]);
  const [user, setUser] = useState([]);


  useEffect(() => {
    const getPhotos = async () => {
      try {
        const photoData = await axios.get(
          "https://jsonplaceholder.typicode.com/albums"
        );
        setPhotoData(photoData.data);
      } catch (error) {
        console.log(error);
      }
    };

    getPhotos();
  }, []);


useEffect(() => {
         //code for finding user. no external api used.
        setUser(user);
      }
    }
  }, []);


  const passedProps = {
    ...pageProps,
     photoData,
     user
  };

  return (
            ...
          <Component {...passedProps} /> 
   )
  1. Then I pass the data (photodata) from a Home component to a (app.js 's) grandchild component, an Photo component
export default function Home({ photoData, user }) {
 return(
          <Photo photoData={photoData} user={user} />
)

  1. In Photo component, I am receiving photoData and trying to set a state for photoArr with the default state of photoData. When the entire app is first loaded, the photoData is passed down to the Photo component successfully that it sets the state without any issue.
    But the main problem is that when I am in the Photo page (photos are loaded) and refresh the page, then it does not set the state for photoArr with photoData. Even though I can console log photoData received from app.js, it does not set state, photoArr, with the default state, photoData.
export default function Photo({ photoData, user }) {

  const [photoArr, setPhotoArr] = useState(photoData); 
//I have this as state because I change this array 
//later on in this component (doing CRUD on the photo array).
  

 console.log(photoData); // this returns the array received from app.js
 console.log(photoArr);  // [].   returns an empty array
 console.log(user); // returns the user object received from app.js.

return (
<div>
 {photoArr.length > 0 ? 
  .... code mapping photoArr 
  : "Data is empty"       //It returns this comment when I refresh the page
}
</div>
)

As you can see above, when I refresh the page, I get "Data is empty" meaning photoArr was not set even with the given default state. If I keep refreshing the page multiple times, it still shows a blank page. From my research, it's due to setting state being asynchronous? So then how can I fix this problem?

  • Is the function in your `useEffect` 'getPhotos' or 'getPhotoData' ? You seem to be using two different functions in the code you posted ? If possible, can you make a codesandbox for demo ? – Bao Huynh Lam Mar 24 '22 at 02:02
  • @BaoHuynhLam sorry that's a typo! I will try to make a demo – user18553387 Mar 24 '22 at 02:06

1 Answers1

1

Try this: (In your Photo page)

const [photoArr, setPhotoArr] = useState(null); 

useEffect(() => {
    if(photoData.length) setPhotoArr(photoData) // If not empty, set the Arr
},[photoData]} // We listen to photoData's change

On page load, there aren't any data in your photoData, and as it pass down to Photo component, react remembers that state. But with useEffect listen to photoData's change, we can setPhotoArr once the getPhotos function got the data back.

Enfield Li
  • 1,952
  • 1
  • 8
  • 23
  • Oh wow tried it and fixed it!!! I have a question about that listening part. If I do not pass in photoData, [photoData], inside useEffect, and just pass in an empty [ ] instead, would react NOT set state because at the moment I refresh the page, photoData has not been passed down yet?? So when I pass in [photoData] instead of an empty arr, react will see if photoData is changed(api re-fetched) in app.js and useeffect in photo.js catches that state change and react to it by setting state for photo arr? – user18553387 Mar 24 '22 at 02:25
  • To be honest, I got myself familiared with the useage of useEffect fairly recently, I guess you'll have to experiment more, I got to know these when I tried to integrate socket.io with react, the more I play around with it, the more I get to understand the power of it, and the relationship with class based componentDidMount side of things. – Enfield Li Mar 24 '22 at 03:51