Solución:
Sugiero ver la respuesta de Dan Abramov (uno de los mantenedores centrales de React) aquí:
Creo que lo estás complicando más de lo necesario.
function Example() {
const [data, dataSet] = useState<any>(null)
useEffect(() => {
async function fetchMyAPI() {
let response = await fetch('api/data')
response = await response.json()
dataSet(response)
}
fetchMyAPI()
}, [])
return <div>{JSON.stringify(data)}</div>
}
A largo plazo, desalentaremos este patrón porque fomenta las condiciones de carrera. Por ejemplo, cualquier cosa podría suceder entre el comienzo y el final de su llamada, y podría haber obtenido nuevos accesorios. En su lugar, recomendaremos Suspense para la obtención de datos, que se parecerá más a
const response = MyAPIResource.read();
y sin efectos. Pero mientras tanto, puede mover las cosas asíncronas a una función separada y llamarla.
Puedes leer más sobre el suspenso experimental aquí.
Si desea utilizar funciones en el exterior con eslint.
function OutsideUsageExample() {
const [data, dataSet] = useState<any>(null)
const fetchMyAPI = useCallback(async () => {
let response = await fetch('api/data')
response = await response.json()
dataSet(response)
}, [])
useEffect(() => {
fetchMyAPI()
}, [fetchMyAPI])
return (
<div>
<div>data: {JSON.stringify(data)}</div>
<div>
<button onClick={fetchMyAPI}>manual fetch</button>
</div>
</div>
)
}
Si va a utilizar useCallback, mire un ejemplo de cómo funciona useCallback. Salvadera.
import React, { useState, useEffect, useCallback } from "react";
export default function App() {
const [counter, setCounter] = useState(1);
// if counter is changed, than fn will be updated with new counter value
const fn = useCallback(() => {
setCounter(counter + 1);
}, [counter]);
// if counter is changed, than fn will not be updated and counter will be always 1 inside fn
/*const fnBad = useCallback(() => {
setCounter(counter + 1);
}, []);*/
// if fn or counter is changed, than useEffect will rerun
useEffect(() => {
if (!(counter % 2)) return; // this will stop the loop if counter is not even
fn();
}, [fn, counter]);
// this will be infinite loop because fn is always changing with new counter value
/*useEffect(() => {
fn();
}, [fn]);*/
return (
<div>
<div>Counter is {counter}</div>
<button onClick={fn}>add +1 count</button>
</div>
);
}
Cuando usas una función asíncrona como
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);
}
}
devuelve una promesa y useEffect
no espera que la función de devolución de llamada devuelva Promise, sino que espera que no se devuelva nada o que se devuelva una función.
Como solución alternativa para la advertencia, puede utilizar una función asíncrona que se invoca automáticamente.
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);
}
})();
}, []);
o para hacerlo más limpio, puede definir una función y luego llamarla
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();
}, []);
la segunda solución hará que sea más fácil de leer y lo ayudará a escribir código para cancelar solicitudes anteriores si se activa una nueva o guardar la última respuesta de solicitud en el estado
Códigos de trabajo y caja
Hasta que React proporcione una mejor manera, puede crear un ayudante, useEffectAsync.js
:
import { useEffect } from 'react';
export default function useEffectAsync(effect, inputs) {
useEffect(() => {
effect();
}, inputs);
}
Ahora puede pasar una función asíncrona:
useEffectAsync(async () => {
const items = await fetchSomeItems();
console.log(items);
}, []);
Actualizar
Si elige este enfoque, tenga en cuenta que es de mala forma. Recurro a esto cuando sé que es seguro, pero siempre es de mala forma y fortuito.
Suspense for Data Fetching, que aún es experimental, resolverá algunos de los casos.
En otros casos, puede modelar los resultados asíncronos como eventos para que pueda agregar o quitar un oyente según el ciclo de vida del componente.
O puede modelar los resultados asincrónicos como Observable para que pueda suscribirse y darse de baja según el ciclo de vida del componente.