我到处搜索,所有类似的帖子要么不适用,要么没有效果.我有一个非常简单的Reaction应用程序(v18.2.0),我想在我的应用程序中使用useEffect进行一些API调用和其他逻辑渲染.我的理解是,这应该只在提供空数组作为参数时触发一次.

Index.js:

import React from "react";
import App from "./src/App";

import { createRoot } from "react-dom/client";
const container = document.getElementById("root");
const root = createRoot(container);
root.render(<App />);

App.js:

import React, { useEffect } from "react";

const App = () => {
  useEffect(() => {
    console.log("trigger app");
  }, []);

  return <div />;
};

export default App;

Index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My App</title>
    <script defer src="main.js"></script>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

Webpack配置:

module.exports = {
  mode: "development",
  entry: "./index.js",
  output: {
    path: path.resolve(__dirname, "public"),
    filename: "main.js",
  },
  target: ["web", "es5"],
  stats: { children: true },
  devServer: {
    port: "9500",
    static: ["./public"],
    open: true,
    hot: true,
    liveReload: true,
  },
  devtool: "inline-source-map",
  resolve: {
    extensions: [".js", ".jsx", ".json"],
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: "babel-loader",
      },
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./public/index.html",
    }),
    new CleanWebpackPlugin(),
  ],
};

查看this post,我已经验证了我没有使用严格模式,似乎没有任何触发重新渲染,该组件没有被使用一次以上.

推荐答案

UseEffect挂钩始终至少执行两次.即使在使用空的依赖项数组时

useEffect(()=>{}, [])

第一次在组件挂载到DOM之前执行,第二次在挂载到DOM之后执行.

如果您想克服这个问题,并且只运行一次useEffect,那么可以应用一个定制的钩子来检测组件是否已安装.

通常,人们使用ref将其作为可重用的自定义挂钩apply.或者他们通过使用useState()将逻辑直接应用到他们的代码中

创建它非常简单:

使用状态:

const [mounted, setMounted] = React.useState(false);
  React.useEffect(() => {
    setMounted(true);
  }, []);
  if (!mounted) return <Button disabled label="Please wait..."/>;
  else return <Button enabled />;

或者,如果您愿意,使用参考:

import React, { useEffect, useRef } from 'react'

export default function useIsMounted() {
  const didMountRef = useRef(false)
  useEffect(() => {
    didMountRef.current = true
  })

  return Boolean(didMountRef.current)
}

然后,您可以在要检测组件是否已挂载的任何组件中使用它:

import useIsMounted from '@lib/useIsMounted'
const App = ()=> {
  const isMounted = useIsMounted()
  useEffect(()=> {
    if(!isMounted) return
    // else, here, execute the following code only once, and after mount:
    console.log("you'll see me once if you disable strict mode")
  }, [])
}

如果你愿意,已经有一个npm包用于这个钩子,你可以下载它from here:

$ npm i use-is-mounted-ref

然后以同样的方式:

import useIsMounted from 'use-is-mounted-ref';

// ... etc

根据我的经验,使用带有ref的可重用定制钩子方法是任何场景的最终解决方案.

Reactjs相关问答推荐

MUImaterial -ui-如何将文本字段和 Select 分组?

客户端组件中服务器组件的两难境地

在Next.js中实现动态更改的服务器组件

使用useReducer时,props 未从父级传递给子或孙级

梅X折线图无响应

在新屏幕上显示照片时出现问题-react

当useEffect和onClick处理程序都调用useCallback函数时,有没有办法对useEffect产生额外的影响?

React组件未出现

定位数组中的一项(React、useState)

当我无法引用模态组件时,如何使模态组件在 Next.js/React 中管理自己的状态?

单击按钮不会切换组件(当按钮和组件位于两个单独的文件中时)

在 React 中将 MUI 样式外包到单独的文件中?

Reactjs:MUI5:MobileDateTimePicker API:如何自定义日历中的文本

如何在我的自定义主题中样式化MUI TreeItem组件

如何让 useEffect 在 React.JS 中只运行一次?

Redux Toolkit 配置,是否适用于全栈应用程序?

Storybook - 无法解析generated-stories-entry.cjs/字段browser不包含有效的别名配置

模块解析失败:意外令牌 (257:106) 您可能需要适当的加载程序来处理此文件类型

我在使用 Elements of stripe 时使用 React router v6

React中`onScroll`和`onScrollCapture`之间的区别?