You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React集成Firebase v9时创建用户同步写入Firestore出现'doc is not a function'错误及实现方案咨询

Hey there, let's fix that "doc is not a function" error and get your user data saving to Firestore properly!

What's causing the error?

The main issue is a variable name collision. In your original onSnapshot callback, you used doc as the parameter for each document in the query snapshot:

querySnapshot.docs.forEach((doc) => { ... })

But you also imported the doc function from Firebase Firestore to create document references. Inside that loop, JavaScript prioritizes the local doc variable (the document object) over the imported function—so when you tried to call doc(db, "users", username), it was trying to run a document object like a function, hence the error.

Other improvements we'll make

  • Replace the inefficient "loop through all users" username check with a direct Firestore document lookup (way faster, especially as your user base grows).
  • Clean up duplicate useEffect blocks that handle alert timeouts.
  • Fix the missing useState import (you were using it but forgot to import it from React).

Fixed Code

import React, { useState, useEffect } from "react"; // Added missing React imports
import Box from "@mui/material/Box";
import OutlinedInput from "@mui/material/OutlinedInput";
import Button from "@mui/material/Button";
import Alert from "@mui/material/Alert";
import { Link, Outlet } from "react-router-dom";
import { setDoc, serverTimestamp, doc, getDoc } from "firebase/firestore"; // Removed unused imports
import { createUserWithEmailAndPassword } from "firebase/auth";
import { db, auth } from "../../../firebase";
import IGLogo from "../../../images/instagram-logo.png";
import "./SignUpForm.scss";

function SignUpForm() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [username, setUsername] = useState("");
  const [successalert, setSuccessAlert] = useState(undefined);
  const [failalert, setFailAlert] = useState(undefined);

  // Handle success alert timeout
  useEffect(() => {
    if (!successalert) return;
    const timeId = setTimeout(() => setSuccessAlert(undefined), 3000);
    return () => clearTimeout(timeId);
  }, [successalert]);

  // Handle failure alert timeout
  useEffect(() => {
    if (!failalert) return;
    const timeId = setTimeout(() => setFailAlert(undefined), 3000);
    return () => clearTimeout(timeId);
  }, [failalert]);

  const instagramSignUp = async (event) => { // Switched to async/await for cleaner code
    event.preventDefault();

    try {
      // Step 1: Check if username already exists in Firestore
      const userDocRef = doc(db, "users", username);
      const userDocSnap = await getDoc(userDocRef);

      if (userDocSnap.exists()) {
        setFailAlert({ type: "userexist" });
        return; // Exit early if username is taken
      }

      // Step 2: Create auth user if username is available
      const userCreated = await createUserWithEmailAndPassword(auth, email, password);
      
      // Step 3: Save user data to Firestore
      await setDoc(userDocRef, {
        uid: userCreated.user.uid, // Optional: Link auth UID to Firestore document
        email: email,
        timestamp: serverTimestamp(),
      });

      setSuccessAlert({ type: "success" });
      console.log("User created in both Auth and Firestore");

    } catch (error) {
      console.error("Signup error:", error.message);
      // Add more specific error handling here if needed (e.g., invalid email format)
    }
  };

  return (
    <>
      <div className="component__signupalerts">
        {successalert?.type === "success" && (
          <Alert variant="filled" severity="success">
            Account Created Successfully. Please check your Email for Verification.
          </Alert>
        )}
        {failalert?.type === "userexist" && (
          <Alert variant="filled" severity="error">
            Username already taken
          </Alert>
        )}
      </div>
      <div className="component__signupform">
        <img src={IGLogo} alt="Instagram Logo" /> {/* Added descriptive alt text */}
        <Box component="form" className="component__signupform--box">
          <OutlinedInput
            className="component__loginform--input"
            type="text"
            placeholder="Username"
            value={username}
            onChange={(e) => setUsername(e.target.value)}
          />
          <OutlinedInput
            className="component__signupform--input"
            type="email"
            placeholder="Email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
          />
          <OutlinedInput
            className="component__signupform--input"
            type="password"
            placeholder="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
          />
          <Button
            className="component__signupform--button"
            type="submit"
            variant="contained"
            onClick={instagramSignUp}
          >
            Sign Up
          </Button>
          <Link to="/" className="component__signupform--button">
            Sign In
          </Link>
        </Box>
      </div>
      <Outlet />
    </>
  );
}

export default SignUpForm;

Key Changes Explained

  1. Fixed variable collision: We removed the problematic onSnapshot loop entirely and replaced it with a direct document lookup using getDoc, eliminating the name conflict with the imported doc function.
  2. Async/Await syntax: Replaced nested .then() chains with async/await to make the code easier to read and debug.
  3. Efficient username check: Instead of loading all users, we only check the specific document ID (your username) directly—this is a single, fast read operation.
  4. Cleaned up alerts: Combined duplicate useEffect blocks and added dependencies to prevent unnecessary re-runs.
  5. Linked auth UID: Added uid: userCreated.user.uid to the Firestore document (optional but useful for linking auth users to their Firestore data later).

内容的提问来源于stack exchange,提问作者hiimwillow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 17:27:29