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.StrictMode时ReactJS的特性。StrictMode为它的后代节点激活额外的检查和警告。因为应用程序不应该崩溃的情况下,任何不良的做法在代码。我们可以说StrictMode是一个安全检查,用于两次验证组件以检测错误。

你会得到这个<React。组件根的StricyMode>。

root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

如果你想限制组件渲染两次,你可以删除<React。StrictMode>并检查它。但是在糟糕的代码实践中,使用StrictMode来检测运行时错误是必要的。

其他回答

我使用这个作为我的替代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 () => {}
  }, [])

}

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

我遇到过这样的问题:

const [onChainNFTs, setOnChainNFTs] = useState([]);

将触发useEffect两次:

useEffect(() => {
    console.log('do something as initial state of onChainNFTs changed'); // triggered 2 times
}, [onChainNFTs]);

我确认组件MOUNTED ONLY ONCE和setOnChainNFTs没有被调用不止一次-所以这不是问题所在。

我通过将onChainNFTs的初始状态转换为null并进行空检查来修复它。

e.g.

const [onChainNFTs, setOnChainNFTs] = useState(null);
useEffect(() => {
if (onChainNFTs !== null) {
    console.log('do something as initial state of onChainNFTs changed'); // triggered 1 time!
}
}, [onChainNFTs]);

我使用CodeSandbox和删除防止了这个问题。

CodeSandbox_sample

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

正如其他人已经指出的那样,这很可能是由于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)
}

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