Search code examples
javascriptreactjsreact-tsx

Data from API call are stored in a Array but when i try to use that array in a function for further use it shows that array is empty . why?


React code for storing Data from API to an Array and Using the same Array's event_date value for further use.

export const UpcomingHolidays = (props: UpcomingHolidaysProps) => {
  const [holidayPlans, setHolidayPlans] = useState([]);

  const [dateArray, setDate] = useState([]);

  useEffect(() => {
    getHolidayPlans();
  }, []);

  const getHolidayPlans = async () => {
    const holidayResp = await PortalHolidayService.getInstance().getHolidayPlans();
    if (holidayResp) {
      setCities(() => holidayResp.cityModule);
      setHolidayPlans(() => holidayResp.holidayModule);
      setDate(() => holidayResp.holidayModule);
    }
    let today = new Date();
    console.log(holidayPlans);
    holidayPlans.filter((date) => {
      const eventDate = new Date(date.event_date);
      console.log(eventDate);
    });
  };

So what the thing is when i use the Same (holidayPlans) array to display some contents in html it shows the values and displays properly but when i use inside a function it shows there is no data inside the array .

console.log(holidayPlans) shows this

Same Array used to display in html


Solution

  • Here's a challenge: write a JavaScript function useState such that the console.log outputs a 4 and then a 5:

    function render() {
      let [thing, setThing] = useState(4);
      console.log(thing); // 4
      setThing(5);
      console.log(thing); // 5
    }
    

    No matter what you do, you'll never be able to write this function, because no external JavaScript function will be able to set the value of the thing variable; that's because an external JavaScript has no way to modify the thing variable. All useState would be able to do is set its own internal state and change what it returns. Silly example here:

    let hiddenState;
    function useState(initialValue) {
      if (hiddenState === undefined) {
        hiddenState = initialValue;
      }
      const setState = value => {
        hiddenState = value;
      }
      return [hiddenState, setState];
    }
    

    That means render will only be able to get a new value if useState is called again:

    function render() {
      let [thing, setThing] = useState(4);
      console.log(thing); // 4
      setThing(5);
    
      [thing, setThing] = useState(4);
      console.log(thing); // 5
    }
    

    This is essentially what useState does but in a way where the hidden state is unique per instance. As you can see, setState is to be considered "asynchronous" in that state changes aren't reflected until the next render. setState queues up a re-render request. The next time your render function is called, useState will be called again, and it will return a new value.

    Notice with these code modifications, rather than us referencing the state variable before it has updated, we can still reference your response object to get the data:

    export const UpcomingHolidays = (props: UpcomingHolidaysProps) => {
    
      // On the first rendering of `UpcomingHolidays`, holidayPlans will be [].
      // After setHolidayPlans is called, a re-render will be queued, and this
      // UpcomingHolidays  function will be called again. When useState is called
      // the second time, it will have the value passed into setHolidayPlans.
      const [holidayPlans, setHolidayPlans] = useState([]);
    
      // Same for dateArray.
      const [dateArray, setDate] = useState([]);
    
      useEffect(() => {
        getHolidayPlans();
      }, []);
    
      async function getHolidayPlans() {
        const holidayResp = await PortalHolidayService.getInstance().getHolidayPlans();
        if (!holidayResp) {
          return;
        }
    
        // These will flag the component as needing to re-render after the effect
        // completes. They do not change the local variables; they update the
        // internal data of the useState hooks so that the next time those useState
        // calls occur, they'll return new values.
        setCities(holidayResp.cityModule);
        setHolidayPlans(holidayResp.holidayModule);
        setDate(holidayResp.holidayModule.map(date => new Date(date.event_date));
    
        // If you want to log here, don't reference state, which hasn't updated yet.
        // Either store response data as variables or reference the response itself.
        console.log('Holidays are', holidayResp.holidayModule);
      }
    
      return <div>Your content</div>;
    }