Не удается прочитать свойства неопределенного (чтение «indexOf») с помощью модульной реакции Firebase v9 JS

# #reactjs #firebase #google-cloud-firestore

Вопрос:

Я получил эту простую форму, которая регистрирует пользователей и отправляет данные uid и электронной почты в коллекцию в firestore, используя последнюю версию Firebase 9 w/ modular. Аутентификация работает отлично, но часть firestore-нет. Это выдает мне ошибку:

 TypeError: Cannot read properties of undefined (reading 'indexOf')
at Function.fromString (path.ts:229)
at Ac2 (reference.ts:374)
at Login.jsx:29
 

Я не знаю, что это значит, я пытаюсь загрузить электронную почту и данные uid зарегистрированного пользователя в firestore с порядком «пользователи / (и здесь идентификатор пользователя)/ все данные пользователя», но выдает мне эту ошибку.

Я оставляю свой код:

 import React, { useState, useEffect, useCallback } from 'react'
import { auth, db } from "../firebase"
import { createUserWithEmailAndPassword } from "firebase/auth";
import { collection, doc, addDoc, setDoc } from "firebase/firestore"; 



function Login() {
    const [email, setEmail] = useState('')
    const [pass, setPass] = useState('')
    const [error, setError] = useState('')
    const [userData, setUserData] = useState('')

    const ProcessData = e => {
        e.preventDefault()
        registro()
    }

    const registro = useCallback(async() => {

        try {
            await createUserWithEmailAndPassword(auth, email, pass)
            .then((userCredential) => {
                const user = userCredential.user;
                setUserData(user)
            })
            
            
            await addDoc(collection(db, 'users', userData.uid), {
                email: userData.email,
                uid: userData.uid
              })
                
            
            
            setEmail('')
            setPass('')
            setError('')

        } catch (error) {
            const errorCode = error.code;
            const errorMessage = error.message;

            setError(errorMessage)
            console.log(error)
        }
            
    }, [email, pass, error, userData])

    return (
        <div>
            <h3>Registro</h3>
            <form onSubmit={ProcessData}>
                <label>Email Adress</label>
                <input
                type="email"
                placeholder="Email Address"
                onChange={e => setEmail(e.target.value)}
                value={email}
                />
                <label>Password</label>
                <input
                type="password"
                placeholder="Password"
                onChange={e => setPass(e.target.value)}
                value={pass}
                />
                <button type="submit">Registrarse</button>
            </form>
        </div>
    )
}

export default Login
 

Комментарии:

1. В предоставленном вами фрагменте кода нет вызова кода .indexOf . Конечно, к ошибке прилагается трассировка стека, которая сообщает вам, откуда произошла ошибка. Можете ли вы обновить свой вопрос, чтобы включить полное сообщение об ошибке и трассировку стека?

2. @DrewReese я обновляю все сообщение об ошибке, которое меня выбрасывает, проверьте это c:

3. добавьте часть вашего кода, в которой вы вызываете .indexOf

4. Что такое строка 29 Login компонента?

5. Привет @PeterO. Это то, что нигде в моем коде я не использую indexOf, я не могу найти строку кода, где она ссылается на «indexOf».

Ответ №1:

Вам не обязательно считывать данные из userData состояния при добавлении документа. Попробуйте передать параметры непосредственно из user возвращаемого объекта:

 try {
  const { user } = await createUserWithEmailAndPassword(auth, email, pass)
  setUserData(user)
  
  await setDoc(doc(db, 'users', user.uid), {
  //    ^^^    ^^^<-- DocumentReference and not CollectionReference
    email: user.email,
    uid: user.uid
  })
                
} catch (e) {
  console.log(e)
}
 

Кроме того, вы передавали 2 сегмента пути, в collection() которых может быть возвращена ошибка, так как путь ссылки на коллекцию занимает нечетное количество сегментов пути. Если вам нужен идентификатор UID пользователя в качестве идентификатора документа, используйте setDoc , так addDoc как он сгенерирует случайный идентификатор.

Комментарии:

1. Ах, гораздо проще, чем мое решение. Я чувствую себя почти глупо, что не видел этого. Почет.

2. Спасибо! Я не часто использую React, но всякий раз, когда я это делаю, я отдаю приоритет обработке данных над состоянием :’)

Ответ №2:

Вопрос

Строка 29 входа в систему: ожидание addDoc(коллекция(бд, «пользователи», userData.uid), {

userData.uid скорее всего, виновник, так userData как по-прежнему является начальным значением состояния пустой строки ( '' ). Помните, что обновления состояния реакции обрабатываются асинхронно, поэтому setUserData(user) они еще не обновили userData состояние, когда на него ссылаются несколько строк ниже collection(db, 'users', userData.uid) .

Решение

Я предлагаю разделить вторую половину registro функции на useEffect крючок с зависимостью от userData состояния, чтобы выдать побочный эффект добавления документа.

 function Login() {
  const [email, setEmail] = useState('');
  const [pass, setPass] = useState('');
  const [error, setError] = useState('');
  const [userData, setUserData] = useState(null);

  useEffect(() => {
    if (userData) {
      const { email, uid } = userData;
      try {
        addDoc(collection(db, 'users', uid), { email, uid });
      } catch (error) {
        const { code, message } = error;

        setError(message);
        console.log(error);
      }
    }

  }, [userData]);

  const ProcessData = e => {
    e.preventDefault();
    registro();
  }

  const registro = useCallback(async() => {
    try {
      await createUserWithEmailAndPassword(auth, email, pass)
        .then((userCredential) => {
          const { user } = userCredential;
          setUserData(user);
        });
            
      setEmail('');
      setPass('');
      setError('');

    } catch (error) {
      const { code, message } = error;

      setError(message);
      console.log(error);
    }
            
  }, [email, pass, error, userData])

  return (
    ...
  )
}