Home > database >  Why is my React useEffect() hook throwing an Uncaught TypeError and failing to re-render my componen
Why is my React useEffect() hook throwing an Uncaught TypeError and failing to re-render my componen

Time:10-20

EDIT: Added comments for a smoother read

NB: This is my first React.js application, and I've never successfully implemented a useState() or useEffect() hook!

The Problem

I have passed a JS object from a child element (LoginInputForm.js) to its parent element (Login.js), and that is working smoothly. The entire API call that I am performing works perfectly without useEffect(), but does not execute the conditional logic I am expecting it to do, which is "Only perform this API call and update the global context with the result when you get data back from your child element, but until then, delay your process (still going to create a loading section to display in this interim when the functionality is working)". I am doing this because I am hoping to emulate an authentication system in this demo when logging in and only want to log in when I get my user's ID from my custom RESTful API (which is working perfectly, determined from my MANY testing angles). I can see the login screen GUI I have built, but when I try to log in with the details of one of the users in my DB, the frontend basically stops rendering any components (or infinitely renders them?) and complains about the error message in a console.log() statement.

Error Type

React is throwing an Uncaught TypeError. It relates to my two variables in useEffect() called "username" and "password". Even with my if() statement, it still absolutely insists that these two variables be processed.

What I've Tried

I've tried using no dependencies in the useEffect() statement (which caused an infinite loop), I've tried using all the suggested dependencies in the useEffect() statement that React itself suggested (which broke it even more), I've tried removing state dependencies from it as suggested in a Udemy course. I eventually opted to use a function as a dependency (which is bad practice, so I've read) and that still is not working correctly.

Big Ol' Wall of Code

import LoginLogo from "../components/login_components/LoginLogo";
import LoginHeader from "../components/login_components/LoginHeader";
import LoginInputForm from "../components/login_components/LoginInputForm";
import UserInputCard from "../components/ui/UserInputCard";
import React from "react";
import { useContext, useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import CurrentUserContext from "../storage/current-user-context";

function LoginPage() {
  const [isLoggingIn, setIsLoggingIn] = useState(false);
  const navigate = useNavigate();
  const currentUserContext = useContext(CurrentUserContext);
  let loginData;

// This is where I get my loginData object
  function getLoginData(userLoginData) {
    loginData = userLoginData;
    setIsLoggingIn(true);
  }

// What I'm currently struggling with
  useEffect(() => {
    if (isLoggingIn) {
      let username = loginData.username;
      let password = loginData.password;
      let userId;

      if (
        username != null &&
        username !== undefined &&
        password != null &&
        password !== undefined
      ) {
        try {
          userId = fetch(
            `https://<my-domain>/api/users/${username}-${password}`
          ).then((response) => {
            console.log("HTTP Status Code: ", response.status);
            if (!response.ok) {
              console.log(response);
              throw new Error(`Error! Current Status: ${response.status}`);
            } else if (response.ok) {
              return response.json();
            }
          });
        } catch (err) {
          console.log(err);
        }
        currentUserContext.getCurrentUser(userId);
        console.log(userId);
      }
      setIsLoggingIn(false);
    }
  }, [currentUserContext, loginData, getLoginData]);

  return (
    <div>
      <UserInputCard>
        <LoginLogo />
        <LoginHeader />
        <LoginInputForm onGetLoginData={getLoginData} />
      </UserInputCard>
    </div>
  );
}

export default LoginPage;

Please help me, guru's of SO!

CodePudding user response:

Correct me if I am wrong but I feel you are trying to do an API call in the parent when the parent gets the data from the child. If that's the case then the dependencies you are passing in the useEffect don't make sense to me.

I strongly feel that you should pass only react states in the dependency(my personal opinion).

Also, the "loginData" variable is not a state which should be one so that even if the parent re-renders you don't lose what you got from the child.

Changes that you can make in your code:-

  1. Change loginData to be a react state

    const [loginData,setLoginData] = useState();
    
  2. Update getLoginData to:-

     function getLoginData(userLoginData) {
       setLoginData(userLoginData);
     }
    
  3. Update your useEffect to something like this:-

    useEffect(() => {
     if(loginData?.username && loginData?.password){
     // Do your api call here
     }
    },[loginData])
    
  • Related