Estoy tratando de hacer un sitio web de seguimiento de precios criptográficos. Obtengo los datos cada 10 segundos, actualizando la variable prevData de la variable coinList . También quiero acceder a la variable prevData dentro de useEffect, pero dentro de ella la variable no se actualiza, su valor permanece []. Pero si uso prevData fuera de useEffect, los datos están cambiando y puedo usarlos.
Solo quiero el valor de prevData dentro de useEffect que se está actualizando.
function App() { const [coinsList, setCoinsList] = useState([]); const [prevData, setPrevData] = useState([]); let [width, setWidth] = useState(window.innerWidth) useEffect(() => { async function fetchData() { const response = await fetch('api key').then(res => res.json()) setCoinsList(res); setPrevData(res); } fetchData() async function fetchData2() { const res = await fetch('api key').then(res => res.json()) for (let i = 0; i < prevData.length; i++) { if (res[i].current_price > prevData[i].current_price) { let coin = document.getElementById(`${prevData[i].id}`) coin.classList.add('green') console.log(coin) // setTimeout(() => { // coin.classList.remove('green') // }, 1000) } else if (res[i].current_price < prevData[i].current_price) { let coin = document.getElementById(`${prevData[i].id}`) coin.classList.add('red') console.log(coin) // setTimeout(() => { // coin.classList.remove('red') // }, 1000) } else { let coin = document.getElementById(`${prevData[i].id}`) console.log(coin) coin.classList.add('blue') // setTimeout(() => { // coin.classList.remove('blue') // }, 1000) } } setPrevData(res); setCoinsList(res); } setInterval(() => { fetchData2() console.log(prevData) // it is not updating }, 10000) }, []) useEffect(() => { window.addEventListener('resize', () => { setWidth(window.innerWidth) }) }, [window.innerWidth]) console.log(prevData) // it is updatingTiene un cierre en el valor de prevData en el alcance de setInterval , puede usar una referencia para solucionarlo:
const prevDataRef = useRef(); // Keep the ref updates useEffect(() => { prevDataRef.current = prevData; }, []); // no closure useEffect(() => { setInterval(() => { fetchData2(); // use prevDataRef.current console.log(prevDataRef.current); // updated }, 10000); }, []);En fetchData2 un recinto obsoleto del estado de prevData . Se cierra en el ámbito de devolución de llamada de intervalo.
Una forma de remediarlo es usar una referencia React y un useEffect adicional para almacenar en caché una copia del estado prevData al que se puede acceder en la devolución de llamada fetchData2 .
function App() { const [coinsList, setCoinsList] = useState([]); const [prevData, setPrevData] = useState([]); const prevDataRef = React.useRef(prevData); useEffect(() => { prevDataRef.current = prevData; }, [prevData]); ... useEffect(() => { ... async function fetchData2() { const prevData = prevDataRef.current; // <-- grab current value const res = await fetch('api key').then(res => res.json()); for (let i = 0; i < prevData.length; i++) { if (res[i].current_price > prevData[i].current_price) { let coin = document.getElementById(`${prevData[i].id}`); coin.classList.add('green'); } else if (res[i].current_price < prevData[i].current_price) { let coin = document.getElementById(`${prevData[i].id}`); coin.classList.add('red'); } else { let coin = document.getElementById(`${prevData[i].id}`); coin.classList.add('blue'); } } setPrevData(res); setCoinsList(res); } setInterval(() => { fetchData2(); }, 10000) }, []);