最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Calling async function in useEffect causes an ESLint error - Stack Overflow

programmeradmin4浏览0评论

I'm trying to call an async function in a callback in useEffect like this.

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;

Then I got an error.

  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

Then I changed the code like this.

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

Then I got another error.

  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:   react-hooks/exhaustive-deps

My code is almost the same as FAQ and small demo and this article.

My .eslintrc.js

module.exports = {
 env: {
   browser: true,
   es2021: true,
 },
 extends: [
   'plugin:react/remended',
   'airbnb',
   'airbnb/hooks',
   'plugin:@typescript-eslint/remended',
   'plugin:@typescript-eslint/remended-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-ponent-definition": [
       2,
       {
         "namedComponents": "arrow-function"
       }
     ]
 },
 settings: {
   'import/resolver': {
     node: {
       paths: ['src'],
       extensions: ['.js', '.jsx', '.ts', '.tsx']
     },
   },
 },
};

Enmironment

  • MacOS 12.5
  • Node.js 18.7.0
  • TypeScript 4.8.4
  • React 18.2.0
  • React-Bootstrap 2.5.0
  • ESLint 8.25.0
  • @typescript-eslint/eslint-plugin 5.39.0
  • eslint-plugin-react-hooks 4.6.0

Thank you to read. Can anyone solve this?

I'm trying to call an async function in a callback in useEffect like this.

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;

Then I got an error.

  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

Then I changed the code like this.

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

Then I got another error.

  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/link/hooks-data-fetching  react-hooks/exhaustive-deps

My code is almost the same as FAQ and small demo and this article.

My .eslintrc.js

module.exports = {
 env: {
   browser: true,
   es2021: true,
 },
 extends: [
   'plugin:react/remended',
   'airbnb',
   'airbnb/hooks',
   'plugin:@typescript-eslint/remended',
   'plugin:@typescript-eslint/remended-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-ponent-definition": [
       2,
       {
         "namedComponents": "arrow-function"
       }
     ]
 },
 settings: {
   'import/resolver': {
     node: {
       paths: ['src'],
       extensions: ['.js', '.jsx', '.ts', '.tsx']
     },
   },
 },
};

Enmironment

  • MacOS 12.5
  • Node.js 18.7.0
  • TypeScript 4.8.4
  • React 18.2.0
  • React-Bootstrap 2.5.0
  • ESLint 8.25.0
  • @typescript-eslint/eslint-plugin 5.39.0
  • eslint-plugin-react-hooks 4.6.0

Thank you to read. Can anyone solve this?

Share Improve this question edited Oct 23, 2022 at 15:47 skyboyer 23.8k7 gold badges62 silver badges71 bronze badges asked Oct 23, 2022 at 6:00 yukiyuki 3334 silver badges12 bronze badges 3
  • Your first attempt was mostly right. Replace fetchEnBoards(); with fetchEnBoards().then(() => {}).catch(err => console.error(err)); and you should be good – Derek Commented Oct 23, 2022 at 6:14
  • You'll also want to return a function from that useEffect() that cancels the request on unmount if it's still active. You'll need to pass in an AbortController signal to the fetch method and call its .abort() method in that returned function. – Derek Commented Oct 23, 2022 at 6:16
  • fetchEnBoards().then(() => {}).catch(err => console.error(err)); This solution worked. Thank you very much! – yuki Commented Oct 23, 2022 at 8:25
Add a ment  | 

4 Answers 4

Reset to default 2

This is not an error ing from React itself. It is ing from TypeScript, or more specifically, typescript-eslint.

Your first code would run without any exceptions, if it was written in JavaScript, and you didn't activate the eslint-plugin-no-floating-promise rule.

Here's the typescript-eslint documentation about floating promises: https://github./typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/no-floating-promises.md

Here's an article about the same: https://mikebifulco./posts/eslint-no-floating-promises

Why this error?

When you call an async function in your code, it returns a Promise. It's on you to handle the result of the promise using

  1. async/await
  2. then/catch

If you're using neither, it means that you're calling the async function, and are simply not waiting for it to resolve or reject. Your code moves on assuming that everything is fine. This is a floating promise, and your eslint is simply forcing you to handle the Promise.

What happens when you disable the eslint rule and don't handle the Promise?

As long as your asynchronous code resolves as expected, nothing. When one of them fails, and the Promise is rejected, you'll get an uncaught exception. Not quite desirable.

The first time you wrote the code it was right. Reading the error you got seems like you needed to add an try catch block to you function, like:

   useEffect(() => {
        const fetchEnBoards = async () => {
          try {  //This
          const response = await fetch('/api/en-boards');
          const enBoardsJson = await response.json() as EnBoards;
          setEnBoards(enBoardsJson);
          catch(err) {
          console.log(err)
          }
        };
        fetchEnBoards(); // Here
      });
useEffect(() => {
  fetch('/api/en-boards')
    .then(res => res.json() as EnBoards)
    .then(setEnBoards);
}, []);

Note that the empty array passed to useEffect will result in the API call only being made once, instead of on every update.

Looks like you need to read async await

useEffect(() => {
    const fetchEnBoards = async () => {
      const response = await fetch('/api/en-boards');
      const enBoardsJson = await response.json() as EnBoards;
      setEnBoards(enBoardsJson);
    };
    fetchEnBoards()
    .then((response)=>
    console.log("In then block"))
    .catch((err)=>
    console.log("In catch block"))
  });
发布评论

评论列表(0)

  1. 暂无评论