在 useEffect 中调用异步函数会导致 ESLint 错误

Joh*_*ohn 5 javascript typescript reactjs eslint react-hooks

我试图在 useEffect 的回调中调用异步函数,如下所示。

import {useState, useEffect} from 'react';
import Navbar from 'react-bootstrap/Navbar';

interface EnBoards {
  id: number
  name: string
  uri: string
}

const RedichanNav = (): JSX.Element => {

  const [enBoards, setEnBoards] = useState({});

  useEffect(() => {
    const fetchEnBoards = async () => {
      const response = await fetch('/api/en-boards');
      const enBoardsJson = await response.json() as EnBoards;
      setEnBoards(enBoardsJson);
    };
    fetchEnBoards(); // Here
  });

  return (
    <Navbar ></Navbar>);
};

export default RedichanNav;
Run Code Online (Sandbox Code Playgroud)

然后我得到一个错误。

  20:5   error    Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator
 @typescript-eslint/no-floating-promises
Run Code Online (Sandbox Code Playgroud)

然后我把代码改成了这样。

  useEffect(async () => {
    const fetchEnBoards = async () => {
      const response = await fetch('/api/en-boards');
      const enBoardsJson = await response.json() as EnBoards;
      setEnBoards(enBoardsJson);
    };
    await fetchEnBoards();
  });

Run Code Online (Sandbox Code Playgroud)

然后我又遇到了一个错误。

  14:13  error    Effect callbacks are synchronous to prevent race conditions. Put the async function inside:

useEffect(() => {
  async function fetchData() {
    // You can await here
    const response = await MyAPI.getData(someId);
    // ...
  }
  fetchData();
}, [someId]); // Or [] if effect doesn't need props or state

Learn more about data fetching with Hooks: https://reactjs.org/link/hooks-data-fetching  react-hooks/exhaustive-deps
Run Code Online (Sandbox Code Playgroud)

我的代码和FAQ小demo以及这篇文章几乎是一样的。

我的 .eslintrc.js

module.exports = {
 env: {
   browser: true,
   es2021: true,
 },
 extends: [
   'plugin:react/recommended',
   'airbnb',
   'airbnb/hooks',
   'plugin:@typescript-eslint/recommended',
   'plugin:@typescript-eslint/recommended-requiring-type-checking',
   'prettier',
 ],
 parser: '@typescript-eslint/parser',
 parserOptions: {
   ecmaFeatures: {
     jsx: true,
   },
   ecmaVersion: 12,
   sourceType: 'module',
   tsconfigRootDir: __dirname,
   project: ['./tsconfig.json'],
 },
 plugins: [
   'react',
   '@typescript-eslint',
 ],
 "ignorePatterns": [
   ".eslintrc.js"
 ],
 rules: {
   'semi': ['error', 'always'],
   'no-use-before-define': "off",
   "@typescript-eslint/no-use-before-define": "off",
   'import/prefer-default-export': "off",
   'import/extensions': [
       'error',
       {
         js: 'never',
         jsx: 'never',
         ts: 'never',
         tsx: 'never',
       },
     ],
     'react/jsx-filename-extension': [
       'error',
       {
         extensions: ['.jsx', '.tsx'],
       },
     ],
     'react/react-in-jsx-scope': 'off',
     'no-void': [
       'error',
       {
         allowAsStatement: true,
       },
     ],
     "react/function-component-definition": [
       2,
       {
         "namedComponents": "arrow-function"
       }
     ]
 },
 settings: {
   'import/resolver': {
     node: {
       paths: ['src'],
       extensions: ['.js', '.jsx', '.ts', '.tsx']
     },
   },
 },
};
Run Code Online (Sandbox Code Playgroud)

环境

  • 苹果系统 12.5
  • Node.js 18.7.0
  • 打字稿 4.8.4
  • 反应18.2.0
  • React-Bootstrap 2.5.0
  • ESLint 8.25.0
  • @typescript-eslint/eslint-插件 5.39.0
  • eslint-插件-react-hooks 4.6.0

感谢您的阅读。有人能解决这个问题吗?

Kar*_*iam 2

这不是来自 React 本身的错误。它来自 TypeScript,或更具体地说,typescript-eslint来自 .

如果您的第一个代码是用 JavaScript 编写的,并且您没有激活该eslint-plugin-no-floating-promise规则,那么它会毫无异常地运行。

这是typescript-eslint有关浮动承诺的文档:https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/no-floating-promises.md

这是一篇关于相同内容的文章: https ://mikebifulco.com/posts/eslint-no-floating-promises

为什么会出现这个错误?

当您在代码中调用异步函数时,它会返回一个 Promise。您需要使用以下方法来处理承诺的结果

  1. 异步/等待
  2. 然后/抓住

如果您两者都不使用,则意味着您正在调用异步函数,并且只是不等待它解析或拒绝。您的代码将继续假设一切正常。这是一个浮动的 Promise,你的 eslint 只是强迫你处理这个 Promise。

禁用 eslint 规则时会发生什么不处理 Promise 时会发生什么?

只要您的异步代码按预期解析,就什么都没有。当其中一个失败并且 Promise 被拒绝时,您将得到一个未捕获的异常。不太理想。