React useState 挂钩是附加值而不是覆盖
React useState hook is appending values instead of overwriting
所以我想每 5 秒更新一次实时价格,因此我将递归 setTimeout 放入函数中。不幸的是,目前喂价方式是这样的:
- 在启动控制台输出是:未定义和当前价格
- 价格变化后输出为:未定义、旧价格、新当前价格
- 下一次价格变动后:未定义,最旧价格,旧价格,新当前价格
为什么它附加值而不是像往常一样覆盖它们?
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
是异步的,设置它然后立即记录它会显示旧结果。
问题
- 您正在控制台在状态入队后立即记录您的状态,这只会记录当前渲染周期的状态,而不是下一个渲染周期入队的状态。
- 您的
useEffect
钩子 运行 每次组件呈现时,因此您开始多次超时。我怀疑您看到的“附加”是重复超时的结果 运行 同一个回调。
解决方案
- 使用一个空的依赖数组运行组件挂载时效果一次
- 使用间隔 运行 抓取。
- Return 清除任何 运行ning 间隔的清理函数。
- 控制台将更新状态记录在它自己的依赖项中。
代码:
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
所以我想每 5 秒更新一次实时价格,因此我将递归 setTimeout 放入函数中。不幸的是,目前喂价方式是这样的:
- 在启动控制台输出是:未定义和当前价格
- 价格变化后输出为:未定义、旧价格、新当前价格
- 下一次价格变动后:未定义,最旧价格,旧价格,新当前价格
为什么它附加值而不是像往常一样覆盖它们?
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
是异步的,设置它然后立即记录它会显示旧结果。
问题
- 您正在控制台在状态入队后立即记录您的状态,这只会记录当前渲染周期的状态,而不是下一个渲染周期入队的状态。
- 您的
useEffect
钩子 运行 每次组件呈现时,因此您开始多次超时。我怀疑您看到的“附加”是重复超时的结果 运行 同一个回调。
解决方案
- 使用一个空的依赖数组运行组件挂载时效果一次
- 使用间隔 运行 抓取。
- Return 清除任何 运行ning 间隔的清理函数。
- 控制台将更新状态记录在它自己的依赖项中。
代码:
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