I am new to reactJS and am writing code so that before the data is loaded from DB, it will show loading message, and then after it is loaded, render components with the loaded data. To do this, I am using both useState hook and useEffect hook. Here is the code:

问题是,当我检查console.log时,useEffect被触发了两次。因此,代码将两次查询相同的数据,这是应该避免的。

下面是我写的代码:

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

const indexarray=[]; //The array to which the fetched data will be pushed

function Home() {
   const [isLoading,setLoad]=useState(true);
   useEffect(()=>{
      /*
      Query logic to query from DB and push to indexarray
      */
          setLoad(false);  // To indicate that the loading is complete
    })
   },[]);
   if (isLoading===true){
       console.log("Loading");
       return <div>This is loading...</div>
   }
   else {
       console.log("Loaded!"); //This is actually logged twice.
       return (
          <div>
             <div className="posts_preview_columns">
             {indexarray.map(indexarray=>
             <Postspreview
                username={indexarray.username}
                idThumbnail={indexarray.profile_thumbnail}
                nickname={indexarray.nickname}
                postThumbnail={indexarray.photolink}
             />
             )}
            </div>
         </div>  
         );
    }
}

export default Home;

有人能帮助我理解为什么它被调用两次,以及如何正确地修复代码吗? 非常感谢!


当前回答

新的React文档(目前处于测试阶段)有一个章节精确地描述了这种行为:

如何处理效果发射两次在开发

从文档中可以看出:

通常,答案是实现清理功能。清除函数应该停止或撤消Effect正在做的任何事情。经验法则是,用户不应该能够区分Effect运行一次(如在生产中)和设置→清理→设置序列(如您在开发中看到的)。

所以这个警告应该让你仔细检查你的useEffect,通常意味着你需要实现一个清理函数。

其他回答

我在React 18中找到了一个非常好的解释。在React中调用UseEffect两次

注意:在生产中,它可以正常工作。在开发环境中的严格模式下,有意增加两次安装,以处理错误和所需的清理。

我使用这个作为我的替代useFocusEffect。我使用嵌套的react导航堆栈,如选项卡和抽屉,使用useEffect重构并不像预期的那样对我有效。

import React, { useEffect, useState } from 'react'
import { useFocusEffect } from '@react-navigation/native'

const app = () = {

  const [isloaded, setLoaded] = useState(false)


  useFocusEffect(() => {
      if (!isloaded) {
        console.log('This should called once')

        setLoaded(true)
      }
    return () => {}
  }, [])

}

还有一个例子,你在屏幕上导航了两次。

正如其他人已经指出的那样,这很可能是由于React 18.0引入了严格模式功能。

我写了一篇博客文章,解释了为什么会发生这种情况,以及你可以做些什么来解决它。

但如果你只是想看代码,这里:

let initialized = false

useEffect(() => {
  if (!initialized) {
    initialized = true

    // My actual effect logic...
    ...
  }
}, [])

或作为可重复使用的钩子:

import type { DependencyList, EffectCallback } from "react"
import { useEffect } from "react"

export function useEffectUnsafe(effect: EffectCallback, deps: DependencyList) {
  let initialized = false

  useEffect(() => {
    if (!initialized) {
      initialized = true
      effect()
    }
  }, deps)
}

请记住,只有在不得已的情况下才应该使用这种解决方案!

对我来说是严格模式。删除索引处的严格模式组件。TSX或index.jsx

这可能不是理想的解决方案。但我用了一个变通办法。

var ranonce = false;
useEffect(() => {
    if (!ranonce) {

        //Run you code

        ranonce = true
    }
}, [])

尽管useEffect运行两次,但重要的代码只运行一次。