skip to Main Content

I am very new to React JS and Firebase. I tried to https://medium.com/ topic
"Building a Firebase Authentication and Private Route System in a React App"

After modifying the code and trial and error. I’m stuck in AuthProvider.js.
Everytime, I tried to submit a form from SignIn or LogIn Page.. i got an error saying

createUser is not a function
TypeError: createUser is not a function
at handleFormSubmit (http://localhost:3000/main.a5a57c81bfd5076aaa7d.hot-update.js:62:5)
at HTMLUnknownElement.callCallback (http://localhost:3000/static/js/bundle.js:29437:18)

This createUser is passed on via Context in React.

AuthProvider.js

import {
  createUserWithEmailAndPassword,
  onAuthStateChanged,
  signInWithEmailAndPassword,
  signOut,
} from "firebase/auth";
import { createContext, useEffect, useState } from "react";
import PropTypes from "prop-types";
import auth from "./firebaseConfig";

export const AuthContext = createContext("");

const AuthProvider = ({ children }) => {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  const createUser = (email, password) => {
    setLoading(true);
    return createUserWithEmailAndPassword(auth, email, password);
  };

  const loginUser = (email, password) => {
    setLoading(true);
    return signInWithEmailAndPassword(auth, email, password);
  };

  const logOut = () => {
    setLoading(true);
    return signOut(auth);
  };

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (currentUser) => {
      setUser(currentUser);
      setLoading(false);
    });

    return () => {
      unsubscribe();
    };
  }, []);

  const authValue = {
    createUser,
    user,
    loginUser,
    logOut,
    loading,
  };

  return (
    <AuthContext.Provider value={{ authValue }}>
      {children}
    </AuthContext.Provider>
  );
};

AuthProvider.propTypes = {
  children: PropTypes.node.isRequired,
};

export default AuthProvider;

SignUp.js

import { useContext, useState } from "react";
import { AuthContext } from "./AuthProvider";
import { updateProfile } from "firebase/auth";
import { useNavigate } from "react-router-dom";

const SignUp = () => {
  const { createUser, user, loading } = useContext(AuthContext);
  const [selectedImage, setSelectedImage] = useState(null);
  const navigate = useNavigate();


  // If authentication is still loading, display a loading indicator
  if (loading) {
    return (
      <span className="loading loading-dots loading-lg flex item-center mx-auto"></span>
    );
  }

  // If the user is already authenticated, redirect to the home page
  if (user) {
    navigate("/");
  }

  // Handle form submission for user registration
  const handleFormSubmit = (e) => {
    e.preventDefault();

    const email = e.target.email.value;
    const password = e.target.password.value;
    createUser(email, password)
      .then((result) => {
        // Update user profile with display name
        updateProfile(result.user, {
          //displayName: name,
        });
        navigate("/");
        console.log(result);
      })
      .catch((error) => {
        console.log(error);
      });
    e.target.reset();
  };

  // Handle image upload (not shown in the code, but you can add it)

  // Render the sign-up form
  return (
    <div>
      <div className="min-h-screen bg-base-200">
        <div className="hero-content flex-col">
          <div className="card flex-shrink-0 w-full max-w-sm shadow-2xl bg-base-100">
            <div className="card-body">
              <form onSubmit={handleFormSubmit}>
                <div className="form-control">
                  <label className="label">
                    <span className="label-text">Name</span>
                  </label>
                  <input
                    type="text"
                    name="name"
                    placeholder="Name"
                    className="input input-bordered"
                  />
                </div>
                <div className="form-control">
                  <label className="label">
                    <span className="label-text">Email</span>
                  </label>
                  <input
                    type="email"
                    name="email"
                    placeholder="Email"
                    className="input input-bordered"
                  />
                </div>
                <div className="form-control">
                  <label className="label">
                    <span className="label-text">Password</span>
                  </label>
                  <input
                    type="password"
                    name="password"
                    placeholder="Password"
                    className="input input-bordered"
                  />
                </div>
                <div className="form-control mt-6">
                  <button className="btn btn-primary">Sign Up</button>
                </div>
              </form>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

export default SignUp;

I tried to make the Firebase Auth works by SignIn, SignUp page. This link to my AuthProvider page.
I hope the information of Signed In User could go through all components and page via Context, React

2

Answers


  1. Since you are destructuring createUser from the AuthContext you should not use curly brackets in the AuthContext.Provider because it would be value.createUser. See the code below :

    <AuthContext.Provider value={authValue}>

    For more information, you can look at the docs.

    Login or Signup to reply.
  2. Issue

    The code is providing a context value that is an object with only an authValue property.

    const authValue = {
      createUser,
      user,
      loginUser,
      logOut,
      loading,
    };
    
    return (
      <AuthContext.Provider value={{ authValue }}>
        {children}
      </AuthContext.Provider>
    );
    

    Which means the AuthContext value is { authValue } and so if you wish to access the createUser function the code would use authValue.createUser.

    The consuming code, however, is accessing anything but authValue from the AuthContext, so these are all undefined properties.

    const { createUser, user, loading } = useContext(AuthContext);
    

    createUser, user, and loading are all undefined.

    Solution

    Ensure the consumers access correctly what is actually provided.

    If the context values are passed in an authValue property:

    const authValue = {
      createUser,
      user,
      loginUser,
      logOut,
      loading,
    };
    
    return (
      <AuthContext.Provider value={{ authValue }}>
        {children}
      </AuthContext.Provider>
    );
    
    const { authValue: { createUser, user, loading } } = useContext(AuthContext);
    

    If the context values are passed directly:

    const authValue = {
      createUser,
      user,
      loginUser,
      logOut,
      loading,
    };
    
    return (
      <AuthContext.Provider value={authValue}>
        {children}
      </AuthContext.Provider>
    );
    
    const { createUser, user, loading } = useContext(AuthContext);
    

    Be sure to also specify a AuthContext default value that matches the usage/API.

    Example:

    export const AuthContext = createContext({
      createUser: () => {},
      user: null,
      loginUser: () => {},
      logOut: () => {},
      loading: true,
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search