skip to Main Content

I have an app where im using React hooks, useState, useEffect, useContext i have 1 page Login.js and loginStoreContext.js file

Login.js im rendering a basic form with a button which has onClick which takes a function exported SigninWithGoogle function

import React,{useContext} from 'react'
import Body from '../../UI/Card/Body';
import {Form } from 'react-bootstrap';
import MainButton from '../../UI/Button/Button';
import {SigninWithGoogleProvider} from '../../store/loginStoreContext'
const Login = () => {
  return (
    <Body>
      <Form>
        <Form.Group className="mb-3" controlId="exampleForm.ControlInput1">
          <Form.Label>Email address</Form.Label>
          <Form.Control type="email" placeholder="[email protected]" />
        </Form.Group>

        <Form.Group className="mb-3" >
          <Form.Label htmlFor="inputPassword5">Password</Form.Label>
          <Form.Control
            type="password"
            id="inputPassword5"
            aria-describedby="passwordHelpBlock"
          />
          <Form.Text id="passwordHelpBlock" muted>
            Your password must be 8-20 characters long, contain letters and numbers,
            and must not contain spaces, special characters, or emoji.
          </Form.Text>
        </Form.Group>
      </Form>
       <button type="button" onClick={SigninWithGoogleProvider}>Signin with Google</button>
    </Body>
  )
}

export default Login

SigninWithGoogle.js here im only trying to use google login in my react app

import React , {createContext,useState} from "react";
import app from '../firebaseConfig';
import { GoogleAuthProvider, getAuth, signInWithPopup } from "firebase/auth";

export const AppContext = createContext({
    user:{},
    token:'',
})


export const SigninWithGoogleProvider = (props)=>{

    const [userdata,setUserData] =useState({})
    const [token,setToken] = useState('')

    const provider = new GoogleAuthProvider();
    const auth = getAuth(app)

    signInWithPopup(auth,provider)
    .then(result=>{
       // This gives you a Google Access Token. You can use it to access Google APIs.
    const credential = GoogleAuthProvider.credentialFromResult(result);
    const userToken = credential.accessToken;
    
    setToken(userToken)
    // The signed-in user info.
    const user = result.user;
    setUserData(user)
    })
    .catch(error=>{
      console.log(error)
    })

    return <AppContext.Provider value={{
        user:userdata,
        token:token
    }}>
        {props.children}
    </AppContext.Provider>
  }

After research i came to know i cant use hooks inside event if i comment useState the code will work but i need to manage the state in context so i can access my Auth user at any where is there a work solution would help on this?

i tried to research on the issues after researching i came to know that i cant use useState with events but i need the to have them like this to manage my state i cant keep it inside the component

2

Answers


  1. Chosen as BEST ANSWER

    HI all i saw pilchard's comment and after trying i can now add it to my state what i did is i added a function in SigninWithGoogleProvider before i wasnt access it via a function but directly via a provider which is wrong and has to be a function which then will return a state.

    sample on what i did:

    SigninWithGoogle.js

    export const AuthContext = createContext({
    user:{},
    token:'',
    onClickSignWithGoogle:()=>{}
    

    }) export const SigninWithGoogleProvider = (props)=>{

    const [userData, setUserData] = useState({})
    const [token, setToken] = useState('')
    
    
    const onClickSignWithGoogle =()=>{
    
        const provider = new GoogleAuthProvider();
        const auth = getAuth(app)
    
      signInWithPopup(auth, provider)
      .then(result => {
        // This gives you a Google Access Token. You can use it to access Google APIs.
        const credential = GoogleAuthProvider.credentialFromResult(result);
        const userToken = credential.accessToken;
        // setToken(userToken)
        // The signed-in user info.
        const user = result.user;
        //setUserData(user)
        setUserData(user)
        setToken(userToken)
        return {
            user:userData,
            then:token
        }
      })
      .catch(error => {
        console.log("error: " +error)
      })
    }
    
    return <AuthContext.Provider value={{
        user:userData,
        token:token,
        onClickSignWithGoogle:onClickSignWithGoogle,
    }}>
        {props.children}
    </AuthContext.Provider>
    

    }

    Login.js

        const Login = () => {
    
      const ctx = useContext(AuthContext)
      console.log(ctx.user)
    
    const onClickBtn=() =>{
      ctx.onClickSignWithGoogle()
    }
    
      return (
          <MainButton btnType="button" onClickBtn={onClickBtn}>Signin with Google
    </MainButton>
      )
    }
    

  2. From what you have written, it seems the Context is not needed, you just need to pass data from the parent component to the child, as well as a change callback.

    This is a semplification of your code, but I think it’s enough for you to understand. Let me know if you don’t understand something or you want a deeper answer.

    const Login = () => {
      const [userdata, setUserData] = useState({});
      const [token, setToken] = useState("");
    
      const updateStates = (newUserData, newToken) => {
        setUserData(newUserData);
        setToken(newToken);
      };
    
      return (
        <Body>
          <Form>{/* Whatever you want to render here */}</Form>
          <SigninWithGoogleProvider
            userData={userData}
            token={token}
            updateStates={updateStates}>
            <button type="button">Signin with Google</button>
          </SigninWithGoogleProvider>
        </Body>
      );
    };
    
    const SigninWithGoogleProvider = (props) => {
      const provider = new GoogleAuthProvider();
      const auth = getAuth(app);
    
      signInWithPopup(auth, provider).then((result) => {
        // This gives you a Google Access Token. You can use it to access Google APIs.
        const credential = GoogleAuthProvider.credentialFromResult(result);
        const userToken = credential.accessToken;
    
        props.updateStates(result.user, userToken);
      });
    
      return <>{props.children}</>;
    };
    

    What I’ve done here is "Lifting the state up", as suggested in REACT documentation: https://react.dev/learn/sharing-state-between-components#lifting-state-up-by-example

    Basically, you are saving the data in the parent component, and you pass the data to the child. Also, you pass to the child a callback that allows to update the state of the parent.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search