skip to Main Content

I have a front end call to an api that works well:

 login= useUser() ;

  const handleSubmit = async (e: any) => {
    e.preventDefault();
    setLoading((loading) => !loading);
    setResult('');
    const login = useUser()
    console.log('submitted form')
    try {
      
       login(email,password)//subsitute i'de like to make for the api call below\

      
      // const response = await axios.post('/api/login', {email, password} ) // Send as query paramers );
      setIsloggedin(()=> true)

      router.replace('/dashboard')
      
    } catch (error) {
      alert(JSON.stringify(error.response.data.detail));
    }
    finally{
      setLoading((loading) => !loading)
    }
  }

however, i created another file to make the api call from within an usecontext hook so i could use the response as globally available variables for the whole app. To this end i defined a function in the context and wrapped the app in the context provider as follows:

export default function RootLayout({children}: { children: React.ReactNode}) {
  return (
    <html lang="en">

      <body className={inter.className}>
        <UserProvider>{children}</UserProvider>
        
        
        </body>
    </html>
  )
}

The call isnt working, it doesnt access the api because the context is not available.
The context page is as follows:

'use client'

import { ID } from "appwrite";
import { createContext, useContext, useEffect, useState } from "react";
import { account } from '../appwrite'
  
const UserContext = createContext();

export function UserProvider(props) {
  const [user, setUser] = useState(null);

  async function login(email, password) {
    
    const loggedIn = await axios.post('/api/login', {email, password} )
    setUser(loggedIn);
  }
    

  async function register (email, password, name) {
   await axios.post('/api/signup', { email,  password, name} );

  }  

  async function logout() {
    await axios.post('/api/currentuser');
   // await account.deleteSession("current");
    setUser(null);
  }

  async function init() {
    try {
      const loggedIn = await account.get();
      setUser(loggedIn);
    } catch (err) {
      setUser(null);
    }
  }

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

  return (
    <UserContext.Provider value={{ current: user, login, logout, register }}>
      {props.children}
    </UserContext.Provider>
  );
}
export function useUser() {
  return useContext(UserContext) ;
}

I’m getting an empty error alert- seems its not even accessing the global context function.

Could anyone help? i feel like what i m trying to do is simple.

2

Answers


  1. Chosen as BEST ANSWER

    The empty response was because the const login= useuser() was not in brackets. It should be const {login}= useuser()


  2. The issue is that the code is calling the useUser and useRouterseUser hooks in a callback function which breaks the Rules of Hooks. React hooks must be called at the top-level of the component.

    The solution is to move these hook calls outside the submit handler callback.

    const Login = () => {
      const router = useRouter();
      const { login } = useUser();
    
      ...
    
      const handleSubmit = async (e: any) => {
        e.preventDefault();
    
        setLoading(true);
        setResult('');
        
        try {
          await login(email, password);
          setIsloggedin(true);
          router.replace('/dashboard');
        } catch (error) {
          alert(JSON.stringify(error.response.data.detail));
        } finally {
          setLoading(false);
        }
      };
    
      ...
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search