第一天就超出配额了

问题描述 投票:0回答:2

我创建了这个小应用程序来练习 Firebase,第一天,我收到“超出配额”错误。我很确定我自己没有发送那么多请求,一定有什么东西导致了这么多请求,但我不知道是什么。

这是代码:

Auth.js:

import { useEffect, useState } from 'react';
import { auth, googleProvider } from '../config/firebase'; 
import { createUserWithEmailAndPassword, signInWithPopup, signOut } from 'firebase/auth';

export const Auth = () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  useEffect(() => {
    console.log(auth?.currentUser?.email);
  }, [auth?.currentUser?.email]);

  const signIn = async () => { 
    try {
      await createUserWithEmailAndPassword(auth, email, password);
    } catch (err) {
      console.error(err);
    }
  }

  const signInWithGoogle = async () => { 
    try {
      await signInWithPopup(auth, googleProvider);
    } catch (err) {
      console.error(err);
    }
  }

  const logout = async () => {
    try {
      await signOut(auth);
    } catch (err) {
      console.error(err);
    }
  }

  return (
    <div>
      <input 
        type="email" 
        placeholder="Email..."
        onChange={(e) => setEmail(e.target.value)} />
      <input 
        type="password" 
        placeholder="Password..."
        onChange={(e) => setPassword(e.target.value)} />
      <button onClick={signIn}>Sign In</button>
      <button onClick={signInWithGoogle}>Sign In With Google</button>
      <button onClick={logout}>Log out</button>
    </div>
  )
}

应用程序.js

import { useEffect, useMemo, useState } from 'react';
import { Auth } from './components/auth';
import { db, auth, storage } from './config/firebase'; 
import { ref, uploadBytes } from 'firebase/storage';
import { 
  getDocs, 
  collection, 
  addDoc, 
  deleteDoc,
  updateDoc,
  doc } from 'firebase/firestore'; 

import './App.css';

function App() {
  // movies from db collection
  const [movieList, setMovieList] = useState([]);
  const moviesCollectionRef = useMemo(() => collection(db, "movies"), []);
  
  // New movie states
  const [newMovieTitle, setNewMovieTitle] = useState('');
  const [newReleaseDate, setNewReleaseDate] = useState(0);
  const [isNewMovieOscar, setIsNewMovieOscar] = useState(false);

  // Update title state
  const [updatedTitle, setUpdatedTitle] = useState('');

  // File upload state
  const [fileUpload, setFileUpload] = useState(null);

  const onSubmitMovie = async () => {
    try {
      await addDoc(moviesCollectionRef, { 
        title: newMovieTitle,
        releaseDate: newReleaseDate,
        recievedAnOscar: isNewMovieOscar,
        userId: auth?.currentUser?.uid 
      });
    } catch (err) {
      console.error(err);
    }
  }

  const deleteMovie = async (id) => {
    const movieDoc = doc(db, "movies", id); 
    await deleteDoc(movieDoc);
  }

  const updateMovieTitle = async (id) => {
    const movieDoc = doc(db, "movies", id);
    await updateDoc(movieDoc, { title: updatedTitle }); 
  }
  
  useEffect(() => {
    const getMovieList = async () => {
      try {
        const data = await getDocs(moviesCollectionRef); 
        const filteredData = data.docs.map(doc => ({
          ...doc.data(),
          id: doc.id
        }))
        
        setMovieList(filteredData);
      } catch (err) {
        console.error(err);
      }
    }

    getMovieList();
  }, [onSubmitMovie])

  const uploadFile = async () => {
    if (!fileUpload) return;

    const filesFolderRef = ref(storage, `projectFiles/${fileUpload.name}`); 
    try {
      await uploadBytes(filesFolderRef, fileUpload);
    } catch (err) {
      console.error(err);
    }
  }

  return (
    <div className="App">
      <Auth />

      <div>
        <input 
          type="text" 
          placeholder='Movie title...'
          onChange={(e) => setNewMovieTitle(e.target.value)} />
        <input 
          type="number" 
          placeholder='Release date...'
          onChange={(e) => setNewReleaseDate(Number(e.target.value))} />
        <input 
          type="checkbox"
          checked={isNewMovieOscar}
          onChange={(e) => setIsNewMovieOscar(e.target.checked)} />
        <label>Recieved an Oscar</label>
        <button onClick={onSubmitMovie}>Submit movie</button>
      </div>

      <div>
        {movieList.map(movie => (
          <div key={movie.id}>
            <h1 style={{color: movie.recievedAnOscar ? 'green' : 'red'}}>{movie.title}</h1>
            <p>Date: {movie.releaseDate}</p>

            <button onClick={() => deleteMovie(movie.id)}>Delete movie</button>

            <input 
              type="text" 
              placeholder='New title...'
              onChange={(e) => setUpdatedTitle(e.target.value)} />
            <button onClick={() => updateMovieTitle(movie.id)}>Update Title</button>
          </div>
        ))}
      </div>

      <div>
        <input 
          type="file" 
          onChange={(e) => setFileUpload(e.target.files[0])} />
        <button onClick={uploadFile}>Upload File</button>
      </div>
    </div>
  );
}

export default App;

我应该将所有函数包装成

useCallback()
还是什么?

reactjs firebase react-native firebase-authentication
2个回答
1
投票
useEffect(() => {
  const getMovieList = async () => {
    // ...
  }

  getMovieList();
}, [onSubmitMovie])

因为您将

onSubmitMovie
放入依赖数组中,所以每次组件渲染时都会运行此效果。因此,您可以非常快速地拨打许多电话来获取数据。

似乎没有任何理由将其包含在依赖项数组中,因为它从未被使用过。将其更改为空数组以仅获取挂载上的电影

useEffect(() => {
  const getMovieList = async () => {
    // ...
  }

  getMovieList();
}, []);

1
投票

空依赖数组并不是每次电影更新的最佳实践(您也可以使用全局状态来管理它以减少数据查询),并且默认情况下 Next.js ESLint 控件不允许使用空依赖数组,这将引发警告。相反,您应该使用适当的触发器依赖项,例如当表单准备好发送、所有字段都已填写等时,从数据库中获取列表。

示例代码:

...
  const onSubmitMovie = async () => {
    if (!isFormFilled) return; //check all required inputs filled

    try {
      await addDoc(moviesCollectionRef, { 
        title: newMovieTitle,
        releaseDate: newReleaseDate,
        recievedAnOscar: isNewMovieOscar,
        userId: auth?.currentUser?.uid 
      });
      setMoviesUpdated(prev => !prev);
    } catch (err) {
      console.error(err);
    }
  }

  useEffect(() => {
    const getMovieList = async () => {
      try {
        const data = await getDocs(moviesCollectionRef); 
        const filteredData = data.docs.map(doc => ({
          ...doc.data(),
          id: doc.id
        }));
        
        setMovieList(filteredData);
      } catch (err) {
        console.error(err);
      }
    };

    getMovieList();
  }, [moviesUpdated]);
...

确保您的 firestore 安全设置正确;

https://firebase.google.com/docs/firestore/security/get-started

此外,考虑为数据库更新方法添加额外的安全层,例如服务器端数据库连接和客户端的身份验证 API 等。

https://nextjs.org/blog/security-nextjs-server-components-actions

© www.soinside.com 2019 - 2024. All rights reserved.