即使依赖关系不变,useEffect也会在每个渲染器上运行

时间:2019-09-05 09:23:24

标签: reactjs firebase

我在React应用中使用Firebase身份验证。我收到以下错误:

  

未捕获的FirebaseError:Firebase:名为'[DEFAULT]'的Firebase应用程序   存在(app / duplicate-app)。

我正在尝试配置和初始化Firebase应用程序以利用Firebase auth SDK。使用React类基础组件可以正常工作,但是没有任何错误,但是移到React Hooks方面是一个挑战。

发生问题的简单示例:

import React, {useState, useEffect} from 'react';
import './App.css';

import * as firebase from "firebase/app";
import 'firebase/auth';

const App = () => {

  const [emailVal, setEmailVal] = useState('')
  const [passwordVal, setPasswordVal] = useState('')

  const handleChangeEmail = (event) => {
    setEmailVal(event.target.value);
  }

  const handleChangePassword = (event) =>{
    setPasswordVal(event.target.value);
  }

  const handleSubmit = (event) =>{
    event.preventDefault();
    const auth = firebase.auth()
    auth.signInWithEmailAndPassword(emailVal, passwordVal)
      .then(response=>{
        console.log(response)
      });
  }

  const firebaseConfig = {
    apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    authDomain: "xxxxxxxxxxxxxxxxxxxxxxxxxx",
    databaseURL: "xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    projectId: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    appId: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  };

  console.log(firebaseConfig)

  useEffect(()=>{
    console.log("useEffect called")
    firebase.initializeApp(firebaseConfig);
  }, [firebaseConfig])


  return (
    <div className="App">
      <h1>Testing client side authentication</h1>

        <form onSubmit = {handleSubmit}>
          <label>
            Email:
            <input type="text" value={emailVal} onChange={handleChangeEmail} />
          </label>
          <label>
            Password:
            <input type="text"  value={passwordVal} onChange={handleChangePassword}/>
          </label>
          <input type="submit" value="Submit" />
        </form>

    </div>
  );
}

export default App;

当我将console.log放置在useEffect中时,useEffect挂钩似乎在第一个渲染之后运行,这很好。然后,当我在文本输入框中键入内容并重新呈现该组件时,即使firebaseConfig变量未更改,useEffect挂钩也会再次运行。我怀疑每个重新渲染实际上都在创建firebaseConfig变量的新版本,从而触发useEffect挂钩。 为了克服这个问题,我从useEffect挂钩中删除了依赖项,如下所示:

 useEffect(()=>{
    console.log("useEffect called")
    firebase.initializeApp(firebaseConfig);
  }, [])

这很好,但是我收到了警告:

  

React Hook useEffect缺少依赖项:“ firebaseConfig”。要么   包括它或删除依赖项数组react-hooks / exhaustive-deps

所以我的下一步是在useState调用中设置firebaseConfig。但是然后我也收到警告,警告说setFirebaseConfig没有被使用。

我会轻松地将依赖项保留为空,以便useEffect像ComponentDidMount一样工作,但是随后的警告信息使我担心,这可能会导致我的代码出现问题。

从本质上讲,如果我能以某种方式比较firebaseConfig中的实际值并将其添加到useEffect依赖项中,我认为它会起作用,因为一旦加载应用程序,值本身就不会改变。有谁知道该怎么做?

谢谢:)

1 个答案:

答案 0 :(得分:2)

每个渲染都会创建一个新的firebaseConfig对象,这会导致useEffect重新运行。

您可以将firebaseConfig移出组件。

或者您可以使用useMemo钩子,这样firebaseConfig不会在每个渲染器中都创建,就像这样:

const firebaseConfig = useMemo(() => ({
    apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    authDomain: "xxxxxxxxxxxxxxxxxxxxxxxxxx",
    databaseURL: "xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    projectId: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    appId: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}), []);