Reputation: 331
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.org/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/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']
},
},
},
};
Thank you to read. Can anyone solve this?
Upvotes: 6
Views: 8183
Reputation: 9807
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.
Upvotes: 0
Reputation: 673
This is not an error coming from React itself. It is coming 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.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/no-floating-promises.md
Here's an article about the same: https://mikebifulco.com/posts/eslint-no-floating-promises
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
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.
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.
Upvotes: 2
Reputation: 331
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"))
});
Upvotes: -1
Reputation: 81
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
});
Upvotes: 0