Search code examples
javascriptreactjstypescriptgraphqlapollo

proper use of onCompleted for GraphQL mutations


I want to run the query first. The query returns an id which is then required for the mutation. Currently, there's an issue with the order of how both things run from the handleSubmit(). If the mutation is successful, the console should print console.log('Checking');but that does not happen. The only output I get on the console is What's the Idand the value is probably something that was stored in one of my previous attempts. If the id was derived from this particular round of query, I would have seen Workingon the log, but that doesn't happen either.

 const [loadUsers, { loading, data, error }] = useLazyQuery(LoadUsersQuery, {
    variables: {
      where: { email: friendEmail.toLocaleLowerCase() },
    },
    onCompleted: () => getFriendId(),
  });



  const [
    createUserRelationMutation,
    {
      data: addingFriendData,
      loading: addingFriendLoading,
      error: addingFriendError,
    },
  ] = useCreateUserRelationMutation({
    variables: {
      input: {
        relatedUserId: Number(id),
        type: RelationType.Friend,
        userId: 5,
      },
    },
    onCompleted: () => addFriend(),
  });
  const getFriendId = () => {
    console.log('Working');
    if (data) {
      console.log(data);
      if (data.users.nodes.length == 0) {
        console.log('No user');
        setErrorMessage('User Not Found');
      } else {
        console.log('ID', data.users.nodes[0].id);
        setId(data.users.nodes[0].id);
      }
    } else {
      if (error) {
        setErrorMessage(error.message);
      }
    }
  };

  const addFriend = () => {
    console.log('Whats the Id', Number(id));
    if (addingFriendData) {
      console.log('Checking');
      console.log(addingFriendData);
    }
    if (addingFriendError) {
      console.log('errorFriend', addingFriendError.message);
      setErrorMessage(addingFriendError.message);
    }
  };

 const handleSubmit = () => {
    loadUsers();
    createUserRelationMutation();
  };

Before this, I was trying this:

const [id, setId] = useState('');
const [friendEmail, setFriendEmail] = useState('');

const [loadUsers, { loading, data, error }] = useLazyQuery(LoadUsersQuery);
const [createUserRelationMutation, { data: addingFriendData, loading: addingFriendLoading, error: addingFriendError }] = useCreateUserRelationMutation();

const getFriendId = () => {
    console.log('Email', friendEmail.toLocaleLowerCase());
    loadUsers({
      variables: {
        where: { email: friendEmail.toLocaleLowerCase() },
      },
    });
    if (data) {     
        console.log('ID', data.users.nodes[0].id);
        setId(data.users.nodes[0].id);      
    } 
    addFriend();
  };

  const addFriend = () => {
    console.log('Whats the Id', Number(id));
       createUserRelationMutation({
        variables: {
               input: {relatedUserId: Number(id), type: RelationType.Friend, userId: 7 }
            },
       });
       if (addingFriendData){
         console.log('Checking')
         console.log(data);
       }
       if(addingFriendError){
         console.log('errorFriend', addingFriendError.message);
         setErrorMessage(addingFriendError.message);
       }
  }


const handleSubmit = () =>
    {getFriendId();};

However, in this case, the values of the id & other states weren't being updated timely. I was running a graphql query inside getFriendId()that returns an id, followed by a mutation (inside addFriend(), which uses the id, along with an input (email) that the user types in. The problem is that on the first attempt, the mutation works fine and with correct values. However, when I change the email address on the input and run the query/mutation again, the values from my previous attempt are being used.

In the second attempt, the mutation was still using the id that we got in the first attempt.

Edit:

onCompleted: (data) => getFriendId(data),

 const getFriendId = (data: any) => {
    console.log('Working');
    if (data) {
      console.log(data);
      if (data.users.nodes.length == 0) {
        console.log('No user');
        setErrorMessage('User Not Found');
      } else {
        console.log('ID', data.users.nodes[0].id);
        setId(data.users.nodes[0].id);
      }

Updated Code:

 const [friendEmail, setFriendEmail] = useState('');
  const [errorMessage, setErrorMessage] = useState('');

  const [loadUsers, { loading, data, error }] = useLazyQuery(LoadUsersQuery);

  const [
    createUserRelationMutation,
    {
      data: addingFriendData,
      loading: addingFriendLoading,
      error: addingFriendError,
    },
  ] = useCreateUserRelationMutation();


 const getFriendId = () => {
    console.log('Email', friendEmail.toLocaleLowerCase());
    loadUsers({
      variables: {
        where: { email: friendEmail.toLocaleLowerCase() },
      },
    });
    if (data) {
      if (data.users.nodes.length == 0) {
        console.log('No user');
        setErrorMessage('User Not Found');
      } else {
        console.log('ID', data.users.nodes[0].id);
        setId(data.users.nodes[0].id);
        addFriend(data.users.nodes[0].id); 

      }
    } else {
      console.log('No data');
      if (error) {
        setErrorMessage(error.message);
      }
    }
    //addFriend();
  };

  const addFriend = (idd: any) => {
    console.log('Whats the Id', Number(idd));
       createUserRelationMutation({
        variables: {
               input: {relatedUserId: Number(idd), type: RelationType.Friend, userId: 9 }
            },
       });
       if (addingFriendData){
         console.log('Checking')
         console.log(data);
       }
       if(addingFriendError){
         console.log('errorFriend', addingFriendError.message);
         setErrorMessage(addingFriendError.message);
       }
  }

    const handleSubmit = () =>
    {
    getFriendId();
    };

Solution

  • You don’t need state to store ID, instead pass the Id to addFriend method like show below

        const [friendEmail, setFriendEmail] = useState('');
        const [errorMessage, setErrorMessage] = useState('');
    
        const _onLoadUserError = React.useCallback((error: ApolloError) => {
            setErrorMessage(error.message);
        }, []);
    
        const [
            createUserRelationMutation,
            {
                data: addingFriendData,
                loading: addingFriendLoading,
                error: addingFriendError,
                called: isMutationCalled
            },
        ] = useCreateUserRelationMutation();
    
        const addFriend = React.useCallback((idd: Number) => {
            console.log('Whats the Id', idd);
            createUserRelationMutation({
                variables: {
                    input: { relatedUserId: idd, type: RelationType.Friend, userId: 9 }
                }
            });
        }, [createUserRelationMutation]);
    
        const getFriendId = React.useCallback((data: any) => {
            console.log('Email', friendEmail.toLocaleLowerCase());
            if (data) {
                if (data.users.nodes.length == 0) {
                    console.log('No user');
                    setErrorMessage('User Not Found');
                } else {
                    console.log('ID', data.users.nodes[0].id);
                    addFriend(Number(data.users.nodes[0].id));
    
                }
            }
        }, [friendEmail, addFriend]);
    
        const [loadUsers] = useLazyQuery(LoadUsersQuery, {
            onCompleted: getFriendId,
            onError: _onLoadUserError
        });
    
        const handleSubmit = React.useCallback(() => {
            loadUsers({
                variables: {
                    where: { email: friendEmail.toLocaleLowerCase() },
                }
            });
        }, [loadUsers, friendEmail]);
    
        if (!addingFriendLoading && isMutationCalled) {
            if (addingFriendData) {
                console.log('Checking')
                console.log(data);
            }
            if (addingFriendError) {
                console.log('errorFriend', addingFriendError.message);
                setErrorMessage(addingFriendError.message);
            }
        }
    

    Update

    I have updated the above code, please refer to it. I'm assuming useCreateUserRelationMutation does not accept options as argument, if it accepts option then you could use onCompleted and onError just like loadUsers query.