React useState 挂钩是附加值而不是覆盖

React useState hook is appending values instead of overwriting

所以我想每 5 秒更新一次实时价格,因此我将递归 setTimeout 放入函数中。不幸的是,目前喂价方式是这样的:

  1. 在启动控制台输出是:未定义和当前价格
  2. 价格变化后输出为:未定义、旧价格、新当前价格
  3. 下一次价格变动后:未定义,最旧价格,旧价格,新当前价格

为什么它附加值而不是像往常一样覆盖它们?

import React, { useState, useEffect } from 'react';
import TextField from '@material-ui/core/TextField';
import Button from '@material-ui/core/Button';
import Livebsv from './livebsv.js';

const CoinGecko = require('coingecko-api');
const CoinGeckoClient = new CoinGecko();


export default function Calculatorbuy() {
    const [value, setValue] = useState(0);
    
    const [price, setPrice] = useState();

    useEffect(() => {
        const fetchPrice = async () => {
            const result = await CoinGeckoClient.simple.price({
                ids: "bitcoin-cash-sv",
                vs_currencies: "pln",
            });
            setPrice(parseFloat(result.data.['bitcoin-cash-sv'].pln));
            console.log(price);
            setTimeout(fetchPrice, 5000)
        }; 
        fetchPrice(); 
    })

有很多问题。

首先,在没有依赖项的情况下调用 useEffect 意味着每次重新渲染后都会 运行。即 fetchPrice 本身会 运行 递归地获取和更新状态,每次更新都会导致组件重新呈现,从而触发 useEffect,从而 setTimeout 叠加。

参见:https://reactjs.org/docs/hooks-effect.html#example-using-hooks

改为

useEffect(
  () => {
    // your code here
  },
  [],
);

然后它将 运行 仅在挂载上。

其次,如评论中所述,setState是异步的,设置它然后立即记录它会显示旧结果。

问题

  1. 您正在控制台在状态入队后立即记录您的状态,这只会记录当前渲染周期的状态,而不是下一个渲染周期入队的状态。
  2. 您的 useEffect 钩子 运行 每次组件呈现时,因此您开始多次超时。我怀疑您看到的“附加”是重复超时的结果 运行 同一个回调。

解决方案

  1. 使用一个空的依赖数组运行组件挂载时效果一次
  2. 使用间隔 运行 抓取。
  3. Return 清除任何 运行ning 间隔的清理函数。
  4. 控制台将更新状态记录在它自己的依赖项中。

代码:

useEffect(() => {
  const fetchPrice = async () => {
    const result = await CoinGeckoClient.simple.price({
      ids: "bitcoin-cash-sv",
      vs_currencies: "pln",
    });
    setPrice(parseFloat(result.data.['bitcoin-cash-sv'].pln));
  };

  fetchPrice(); // <-- first initial fetch

  const timerId = setInterval(fetchPrice, 5000); // <-- start interval

  return () => clearInterval(timerId); // <-- return cleanup
}, []); // <-- run on mount

useEffect(() => {
  console.log(price); // <-- log updated state
}, [price]); // <-- run on price update