How to re-render the result of a custom hook when data loads

Viewed 479

I am trying to render the number of items resulting from a custom hook. This custom takes some time to fetch the data from a database and returns a count (ie: any integer greater or equal to zero).

My current setup is to call the custom hook and push that value into a useState hook to display the current number of items.

However, this is not working. What is currently occurring is that only the first item from the custom hook is returned, and not the updated item.

// A React Component
// gamePlays holds the amount of items returned from the useLoadSpecficRecords hook.
// However, when data initially loads, the length is `0`, but when loading is finished, the length may increase. 
// This increased length is not represented in the gamePlays variable.
const gamePlays = useLoadSpecficRecords(today).games.length

// I want to set the initial value of selected to the number of game plays, but only 
// `0` is being returned
const [selected, setSelected] = useState({
  count: gamePlays,
})

// This useEffect hook and placed gamePlays as a dependency, but that did not update the value.
  useEffect(() => {
  }, [gamePlays])

These are the logs to indicate that the length does load, but is not being updated in the gamePlays variable:

0
0
0
0
0
2
// useLoadSpecficRecords Hook

import { useState, useEffect } from 'react'
import { API, Auth } from 'aws-amplify'
import { listRecordGames } from '../graphql/queries'

// Centralizes modal control
const useLoadSpecficRecords = (date) => {
  const [loading, setLoading] = useState(true)
  const [games, setData] = useState([])

  useEffect(() => {
    fetchGames(date)
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [date])

  const fetchGames = async (date) => {
    try {
      const formatedDate = await date


      let records = await API.graphql({
        query: listRecordGames,
        variables: {
          filter: {
            owner: { eq: username },
            createdAt: { contains: formatedDate },
          },
        },
      })

      const allGames = records.data.listRecordGames.items
      const filteredGames = allGames.map(({ name, players, winners }) => {
        return {
          gameName: name,
          players: players,
          winners: winners,
        }
      })

      setLoading(false)
      setData(filteredGames)
    } catch (err) {
      console.error(err)
    }
  }

  return { games, loading }
}

export default useLoadSpecficRecords

1 Answers

In the useEffect in your custom hook useLoadSpecficRecords, change the dependecy list from date to games. This should retrigger the useEffect and you should see the updated data.

Here is the new implementation: 

import { useState, useEffect } from 'react';
import { API, Auth } from 'aws-amplify';
import { listRecordGames } from '../graphql/queries';

// Centralizes modal control
const useLoadSpecficRecords = (date) => {
  const [loading, setLoading] = useState(true);
  const [games, setData] = useState([]);

  useEffect(() => {
    fetchGames(date);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [games]); <-- dependency list updated!

  const fetchGames = async (date) => {
    try {
      const formatedDate = date;

      let records = await API.graphql({
        query: listRecordGames,
        variables: {
          filter: {
            owner: { eq: username },
            createdAt: { contains: formatedDate },
          },
        },
      });

      const allGames = records.data.listRecordGames.items;

      const filteredGames = allGames.map(({ name, players, winners }) => {
        return {
          gameName: name,
          players: players,
          winners: winners,
        };
      });

      setLoading(false);
      setData(filteredGames);
    } catch (err) {
      console.error(err);
    }
  };

  return { games, loading };
};

export default useLoadSpecficRecords;

I've also removed an unnecessary await you had before date on line 17.

Related