Search code examples
reactjsaws-amplify

React function with multiple APIs calls


below the code of one of the components in my react application. The following code has multiple issues and is very inefficient - that I would like to discuss:

  1. Async API calls are tightly coupled with each other which it is definitely not best practice, so how to improve this?
  2. How can I pass the userName to the fetchSubs without using useEffect() or do I use useEffect in the wrong way here?
  3. I am thinking about if it is better to use a classical react class because of the issue with the second point and the state management looks not very good.

Thanks in advance and I am happy to discuss this code with you. (I guess, I am doing a few things wrong)

    import React, { useState, useEffect } from 'react';
    import { API,Auth, graphqlOperation } from 'aws-amplify';
    import * as queries from '../../graphql/queries';
    import * as subscriptionsgraph from '../../graphql/subscriptions'
    import { Grid, Table } from 'semantic-ui-react';


    function listReservations() {
      const [reservations, setReservations] = useState([]);
      const [userName, setUserName] = useState([]);

      useEffect(() => {
        fetchUser();
        fetchSubs(userName);
      },[userName]);

       // get username
       const fetchUser = async () => {
          await Auth.currentAuthenticatedUser()
          .then(user => {
            setUserName(user.username);
          }).catch(err => {
            console.log('error: ', err)
          });
        }

      // get subs
      const fetchSubs = async(userName) => {
        const limit = 100;
          API.graphql(graphqlOperation(queries.searchSubtos, {
            limit,
            input: { owner: userName }
          })).then(payload => {
            const data = payload.data.searchSubtos.items;
            fetchReservations(data); // get Reservations
          }).catch(err => {
              console.log('error: ', err)
            });
      } 

      // get Reservations
      const fetchReservations = async (data) => {
        const limit = 100; 

        data.forEach(async (item) => {
          console.log(item.location);
          await API.graphql(graphqlOperation(queries.searchReservations, {
            limit,
            sort: {
              field: 'startDate',
              direction: 'asc'
            },
            filter: {
              location: {
                eq: item.location
              }
            }
          }
          )).then(payload => {
            const data = payload.data.searchReservations.items
            setReservations(data);
          }).catch(err => {
            console.log('error: ', err)
          });
        });
        }

      return (
        <div>
          <Grid centered style={{ marginTop: '15px' }}>
            <Grid.Row>
              <Grid.Column width={12}>
                <Table celled striped>
                  <Table.Header>
                    <Table.Row>
                      <Table.HeaderCell colSpan="3">City </Table.HeaderCell>
                      <Table.HeaderCell colSpan="3">Location</Table.HeaderCell>
                    </Table.Row>
                  </Table.Header>
                  <Table.Body>
                    { reservations.map((rest, i) => (
                      <Table.Row key={i}>
                        <Table.Cell colSpan="3">{rest.city}</Table.Cell>
                        <Table.Cell colSpan="3">{rest.location}</Table.Cell>
                      </Table.Row>
                    ))
                    }
                  </Table.Body>
                </Table>
              </Grid.Column>
            </Grid.Row>
          </Grid>
        </div>
      );
    }
    export default listReservations;

Solution

  • First, if you don't have a username array, then change initial value of username like:

    const [userName, setUserName] = useState(null);
    

    Then, use this to fetch username on page load:

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

    Put 1 more useEffect function, to fetch subs once a valid username is fetched

    useEffect(() => {
      if (username) fetchSubs(username);
    },[username]);