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;

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


当前回答

下面是为您的目的定制的钩子。这对你的情况可能有帮助。

import {
  useRef,
  EffectCallback,
  DependencyList,
  useEffect
} from 'react';

/**
 * 
 * @param effect 
 * @param dependencies
 * @description Hook to prevent running the useEffect on the first render
 *  
 */
export default function useNoInitialEffect(
  effect: EffectCallback,
  dependancies?: DependencyList
) {
  //Preserving the true by default as initial render cycle
  const initialRender = useRef(true);

  useEffect(() => {
   
    let effectReturns: void | (() => void) = () => {};
    
    /**
     * Updating the ref to false on the first render, causing
     * subsequent render to execute the effect
     * 
     */
    if (initialRender.current) {
      initialRender.current = false;
    } else {
      effectReturns = effect();
    }

    /**
     * Preserving and allowing the Destructor returned by the effect
     * to execute on component unmount and perform cleanup if
     * required.
     * 
     */
    if (effectReturns && typeof effectReturns === 'function') {
      return effectReturns;
    } 
    return undefined;
  }, dependancies);
}

其他回答

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

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

index.js > remove < react .jsStrictMode >包装

如果有人使用NextJS 13来这里,为了删除严格模式,你需要在next.config.js文件中添加以下内容:

const nextConfig = {
  reactStrictMode: false
}
module.exports = nextConfig

当我创建项目时,它默认使用“严格模式”,这就是为什么我必须显式设置它。

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

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

        //Run you code

        ranonce = true
    }
}, [])

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

没什么好担心的。当你在开发模式下运行React时。它有时会运行两次。在刺激环境中测试它,您的useEffect将只运行一次。别担心! !