Почему возникает проблема с useState() в Next.js?

Всем привет!
Разрабатываю проект на Next.js с использованием API.
В файле index.js создаю компонет :

<API
  width={isMobile ? '40%' : '17%'}
  className={styles.maxwidth} type={isMobile ? '' : '2'}
  columns={isMobile ? ['название', 'цена', 'изменение'] : ['название', 'символ', 'цена', 'капитализ.', 'курс']}
  template={isMobile ? [
    ['Bitcoin', '???', '?? %']
  ]
  : [
    ['Bitcoin', '???', '?? $', '?? $', '?? %']
  ]}
  func={fetchCryptoRating}
  isMobile={isMobile}
/>

Затем в файле components/API.jsx запускаю функцию, которую передал в компонент, с определенной периодичностью при помощи setInterval():

import React, {useState, useEffect} from 'react'
import Table from '../components/Table.jsx'

const API = ({ columns, template, width = 'auto', type = '', className = '', fake, func, isMobile }) => {
    const [tables, setTables] = useState(template);
    const [prices, setPrices] = useState(false);
    const [color, setColor] = useState(false);
    useEffect(() => {
        setTimeout(() => {
            func(setTables, setPrices, setColor, prices, isMobile)
        }, 10000)
    },[]);

    return (
        <Table
            width={width}
            className={className}
            columns={columns}
            tables={tables}
            type={type}
            fake={fake}
            colors={color}
        />
    )
}

export default API;

И вот файл функции, которую запускаю:

import { cryptoList, cryptoName } from './Data'
import axios from 'axios'

export async function fetchCryptoRating(setTables, setPrices, setColor, prices, isMobile) {
    const tables = []
    const priceData = []
    const colors = []
    const options = {
        method: 'GET',
        url: 'https://binance43.p.rapidapi.com/ticker/24hr',
        headers: {
            'X-RapidAPI-Host': 'binance43.p.rapidapi.com',
            'X-RapidAPI-Key': ''
        }
    };
    const result = await axios.request(options)
    var serverData = result.data.filter(item => cryptoList.indexOf(item.symbol) != -1)
    var count = 0
    serverData.forEach(item => {
        if (prices) {
            if (parseInt(item.lastPrice) > prices[count]) {
                colors.push('#23C14F')
            }
            if (parseInt(item.lastPrice) < prices[count]) {
                colors.push('#FF4545')
            }
            if (parseInt(item.lastPrice) == prices[count]) {
                colors.push('#433532')
            }
        }
        else {
            colors.push('#433532')
        }
        const itemData = isMobile ? [
            cryptoName[count],
            `${parseInt(item.lastPrice)} $`,
            `${parseFloat(item.priceChangePercent).toFixed(2)} %`
        ] : [
            cryptoName[count],
            cryptoList[count].slice(0, 3),
            `${parseInt(item.lastPrice)} $`,
            `${parseInt(item.lastPrice) * 19200000} $`,
            `${parseFloat(item.priceChangePercent).toFixed(2)} %`
        ]
        tables.push(itemData)
        priceData.push(parseInt(item.lastPrice))
        count ++
    })
    setTables(tables)
    setPrices(priceData)
    setColor(colors)
}

Проблема заключается в том, что эти строки:
setTables(tables)
setPrices(priceData)
setColor(colors)
не меняют состояния переменных, заданных при помощи useState() в файле API.jsx. Кто-нибудь может объяснить, с чем это связано. Буду очень благодарен
  • Вопрос задан
  • 194 просмотра
Решения вопроса 1
@id100k
React developer
Потому, что функции-сеттеры отданы, но они потеряли контекст. Вам следует отдать данные в fetchCryptoRating, вернуть обновлённые значения из неё - в реакт компоненте в эффекте их получить обратно. И уже с этими новыми данными вызывать setTables и тд. Именно в эффекте.

Кстати, из эффекта нужно возвращать функцию, которая почистит интервал или таймаут (clearTimeout)
useEffect(() => {
        const intervalId = setInterval(() => {}, 1000)
        
        return () => clearInterval(intervalId)
    }, [])
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы