Когда вы пытаетесь выполнить асинхронную активность внутри хука React useEffect, вы могли видеть следующие предупреждения:
Effect callbacks are synchronous to prevent race conditions. Put the async function inside:
useEffect function must return a cleanup function or nothing
Рассмотрим следующий код:
import { useEffect, useState } from "react"
function App() {
const [posts, setPosts] = useState([])
useEffect(async () => {
try {
const response = await fetch(`https://jsonplaceholder.typicode.com/posts`)
const data = await response.json()
setPosts(data)
} catch (e) {
console.error(e)
}
}, [])
return (
<div className="App">
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
)
}
export default App
Здесь мы передаем асинхронную функцию в хук useEffect. Как вы, возможно, знаете, асинхронные функции возвращают Promise. Однако useEffect ожидает, что функция либо ничего не вернет, либо вернет функцию очистки. Поэтому reacts выдает это предупреждение.
Есть 2 способа исправить это.
Перемещение асинхронного вызова в другую функцию
Мы можем определить другую функцию внутри useEffect и вызвать ее внутри useEffect, как показано ниже:
import { useEffect, useState } from "react"
function App() {
const [posts, setPosts] = useState([])
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(
`https://jsonplaceholder.typicode.com/posts`
)
const data = await response.json()
setPosts(data)
} catch (e) {
console.error(e)
}
}
fetchData()
}, [])
return (
<div className="App">
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
)
}
export default App
Теперь функция, переданная в useEffect, ничего не возвращает, тем самым выполняя условие.
Также вы можете предотвратить состояние гонки, отменив предыдущие запросы.
Использование цепочки .then()
Вместо того чтобы использовать синтаксис async await, мы можем использовать .then()
для разрешения обещания:
import { useEffect, useState } from "react"
function App() {
const [posts, setPosts] = useState([])
useEffect(() => {
fetch(`https://jsonplaceholder.typicode.com/posts`)
.then(response => response.json())
.then(data => {
setPosts(data)
})
.catch(e => {
console.log(e)
})
}, [])
return (
<div className="App">
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
)
}
export default App
Теперь, если вы запустите код, вы больше не должны видеть предупреждение.