How to add firebase authentication data to a firestore collection in React?

Viewed 681

Currently, when a user signs up they are being created as a user in the firebase authentication. I am trying to add that newly created user directly into a firestore collection upon creation.

The following is the AuthContext.js

import React, { useContext, useState, useEffect } from "react";
import { auth } from "../firebase";

const AuthContext = React.createContext();

export function useAuth() {
  return useContext(AuthContext);
}

export function AuthProvider({ children }) {
  const [currentUser, setCurrentUser] = useState();
  const [loading, setLoading] = useState(true);

  function signup (email, password) {
    return auth.createUserWithEmailAndPassword(email, password);
  }

  function login(email, password) {
    return auth.signInWithEmailAndPassword(email, password);
  }

  function logout() {
    return auth.signOut();
  }

  function resetPassword(email) {
    return auth.sendPasswordResetEmail(email);
  }

  function updateEmail(email) {
    return currentUser.updateEmail(email);
  }

  function updatePassword(password) {
    return currentUser.updatePassword(password);
  }

  useEffect(() => {
    const unsubscribe = auth.onAuthStateChanged((user) => {
      setCurrentUser(user);
      setLoading(false);
    });

    return unsubscribe;
  }, []);

  const value = {
    currentUser,
    login,
    signup,
    logout,
    resetPassword,
    updateEmail,
    updatePassword,
  };
  return (
    <AuthContext.Provider value={value}>
      {!loading && children}
    </AuthContext.Provider>
  );
}

The following is Signup.js

import React, { useRef, useState } from 'react'
import { Form, Button, Card, Alert } from "react-bootstrap"
import { Link, useHistory } from "react-router-dom"
import { useAuth } from './contexts/AuthContext'

export default function Signup() {
  const emailRef = useRef()
  const passwordRef = useRef()
  const passwordConfirmRef = useRef()
  const { signup } = useAuth()
  const [error, setError] = useState("")
  const [loading, setLoading] = useState(false)
  const history = useHistory()

async function handleSubmit(e){
    e.preventDefault()
    
    if (passwordRef.current.value !==
      passwordConfirmRef.current.value) {
        return setError('Passwords do not match')
      }

     try{
       setError('')
       setLoading(true)
      await signup(emailRef.current.value,passwordRef.current.value)
      history.push("/")
     } catch {
       setError('Failed to create an account')
     }
     setLoading(false)
     
}

    return (
        <>
          <Card>
            <Card.Body>
              <h2 className="text-center mb-4">Sign Up</h2>
              {error && <Alert variant="danger">{error}</Alert>}
              <Form onSubmit={handleSubmit}>
                <Form.Group id="email">
                  <Form.Label>Email</Form.Label>
                  <Form.Control type="email" ref={emailRef} required />
                </Form.Group>
                <Form.Group id="password">
                  <Form.Label>Password</Form.Label>
                  <Form.Control type="password" ref={passwordRef} required />
                </Form.Group>
                <Form.Group id="password-confirm">
                  <Form.Label>Password Confirmation</Form.Label>
                  <Form.Control type="password" ref={passwordConfirmRef} required />
                </Form.Group>
                    <Button disabled={loading} className="w-100" type="submit">
                    Sign Up
                    </Button>
              </Form>
                <div className="w-100 text-center mt-2">
                    Already have an account? <Link to="/login">Log In</Link>
                </div>
            </Card.Body>
          </Card>
         
        </>
      )
    }

Thank you in advance, any help will be greatly appreciated.

1 Answers

The creation of the user in Firebase Auth will happen no matter what you do, but you can take advantage of that by creating a Cloud Function that triggers everytime a user is created in Firebase auth and then create a new document in Firestore representing that user. Here is a Cloud Function example that does just that:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

const db = admin.firestore();

exports.createUser = functions.auth.user().onCreate((user) => {
    const { uid } = user;

    const userCollection = db.collection('users');

    userCollection.doc(uid).set({
        someData: "123"
    });
});

Also in the documentation you can see how to deploy Cloud Functions, in case you are not familiar with it.

Related