React Hook Warnings для функции async в useEffect: useEffect функция должна возвращать функцию очистки или ничего
Я пытался использовать пример useEffect что-то вроде ниже:
useEffect(async () => {
try {
const response = await fetch('https://www.reddit.com/r/${subreddit}.json');
const json = await response.json();
setPosts(json.data.children.map(it => it.data));
} catch (e) {
console.error(e);
}
}, []);
Ответы
Ответ 1
Предлагаю посмотреть ответ Дана Абрамова (одного из ведущих разработчиков React) здесь:
Я думаю, вы делаете это более сложным, чем нужно.
export default function Example() {
const [data, dataSet] = useState(false)
async function fetchMyAPI() {
let response = await fetch('api/data')
response = await res.json()
dataSet(response)
}
useEffect(() => {
fetchMyAPI();
}, []);
return <div>{data}</div>
}
В долгосрочной перспективе мы будем препятствовать этой модели, потому что она стимулирует условия гонки. Например, между началом и окончанием вызова может произойти все, и вы могли бы получить новые реквизиты. Вместо этого мы рекомендуем Suspense для извлечения данных, который будет больше похож на
const response = MyAPIResource.read();
и никаких эффектов. Но в то же время вы можете переместить асинхронный материал в отдельную функцию и вызвать ее.
Ответ 2
Когда вы используете асинхронную функцию типа
async () => {
try {
const response = await fetch('https://www.reddit.com/r/${subreddit}.json');
const json = await response.json();
setPosts(json.data.children.map(it => it.data));
} catch (e) {
console.error(e);
}
}
он возвращает обещание, и useEffect
не ожидает, что функция обратного вызова вернет Promise, скорее он ожидает, что ничего не возвращается или функция не возвращается.
В качестве обходного пути для предупреждения вы можете использовать самозапускающуюся асинхронную функцию.
useEffect(() => {
(async function() {
try {
const response = await fetch(
'https://www.reddit.com/r/${subreddit}.json'
);
const json = await response.json();
setPosts(json.data.children.map(it => it.data));
} catch (e) {
console.error(e);
}
})();
}, []);
или чтобы сделать его более понятным, вы можете определить функцию и затем вызвать ее
useEffect(() => {
async function fetchData() {
try {
const response = await fetch(
'https://www.reddit.com/r/${subreddit}.json'
);
const json = await response.json();
setPosts(json.data.children.map(it => it.data));
} catch (e) {
console.error(e);
}
};
fetchData();
}, []);
Второе решение облегчит чтение и поможет вам написать код для отмены предыдущих запросов при запуске нового или сохранения последнего ответа на запрос в состоянии
Рабочие коды и коробка
Ответ 3
Пока React не предоставит лучший способ, вы можете создать помощник, useEffectAsync.js
:
import { useEffect } from 'react';
export default function useEffectAsync(effect, inputs) {
useEffect(() => {
effect();
}, inputs);
}
Теперь вы можете передать асинхронную функцию:
useEffectAsync(async () => {
const items = await fetchSomeItems();
console.log(items);
}, []);
Ответ 4
Я прочитал этот вопрос и чувствую, что лучший способ реализации useEffect не упомянут в ответах.
Допустим, у вас есть сетевой вызов, и вы хотели бы что-то сделать, как только получите ответ.
Для простоты давайте сохраним сетевой ответ в переменной состояния.
Возможно, вы захотите использовать действие/редуктор, чтобы обновить магазин с ответом сети.
const [data, setData] = useState(null);
/* This would be called on initial page load */
useEffect(()=>{
fetch('https://www.reddit.com/r/${subreddit}.json')
.then(data => {
setData(data);
})
.catch(err => {
/* perform error handling if desired */
});
}, [])
/* This would be called when store/state data is updated */
useEffect(()=>{
if (data) {
setPosts(data.children.map(it => {
/* do what you want */
}));
}
}, [data]);
Ссылка => https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects