React State Update 正在为 First State Update 工作,但无法进行任何进一步的更新
React State Update Working for First State Update but Failing on any further updates
所以我有一个 React 组件,它会每隔一段时间调用一个函数来获取帐户余额。组件的第一次加载从加载中成功更新,未准备就绪并提取用户帐户余额。
完成交易并在下一次账户余额轮询时,账户余额会在状态和日志中更新为正确的值,但不会在组件 UI(或任何子组件)上更新。我还尝试提取其中一个变量,如下所示为 pcDaiValue。这也会在第一次加载和第一次获取账户余额时更新,但是不会进一步更新,例如在交易之后。状态确实会更新并记录,但是 UI 不会更新以反映此状态。
我最初认为这是之前 post 中的子组件问题,但现在我意识到这是父组件的状态未更新。
如果您查看 pcDaiValue 状态 - 它将在状态而不是 UI 中更新。想知道一个可能的解决方案。
如有任何帮助,我们将不胜感激
下面的代码删除了不相关的部分:
function ProtektDepositCard({
children,
item,
lendingMarketMetrics,
tokenPrices,
}: Props): React.Node {
const [accountBalances, setAccountBalances] = useState({ready:false})
const [pcDaiValue, setPCDaiValue] = useState(0)
useInterval(async () => {
(async function(){
const newAccountBalances = await GetAccountBalances(
web3Context.address,
tokenPrices,
contracts,
[item.underlyingTokenSymbol, item.pTokenSymbol, item.reserveTokenSymbol, item.shieldTokenSymbol, item.coreTokenSymbol],
[item.underlyingTokenDecimals, item.pTokenDecimals, item.reserveTokenDecimals, item.shieldTokenDecimals, item.coreTokenDecimals],
[item.pTokenAddress, item.pTokenAddress, item.shieldTokenAddress, item.shieldTokenAddress, item.pTokenAddress],
[null, item.underlyingTokenSymbol, null, item.reserveTokenSymbol, null]
)
console.log('retrieved account balances')
console.log(newAccountBalances)
console.log('retrieved pcdai')
console.log(pcDaiValue)
if(newAccountBalances['pcdai']){
const pTokenValue = newAccountBalances['pcdai']['token']
setPCDaiValue(pTokenValue)
}
setAccountBalances({...newAccountBalances})
})();
}, 5000)
console.log('logging account balances')
console.log(accountBalances)
return ( (coverage.loading) ? <Card><Card.Body><Dimmer active loader /></Card.Body></Card> :
<AccordionItem
key={accountBalances}
>
<div>PCDAI VALUE: {String(pcDaiValue)}</div>
<Card className="mb-1">
<AccordionItemHeading>
<AccordionItemButton>
<Card.Body>
<Grid.Row alignItems="center" justifyContent="center">
<Grid.Col width={2}>
<Avatar
imageURL={`assets/${item.coreTokenLogo}.png`}
style={{"verticalAlign":"middle"}}
/>
<Text size="h4" align="center" RootComponent="span" className="ml-2">{item.coreToken.toUpperCase()}</Text>
</Grid.Col>
<Grid.Col width={3}>
<Avatar
imageURL={`assets/${item.protocolLogo}.png`}
style={{"verticalAlign":"middle"}}
size="lg"
/>
<Text size="h4" align="center" RootComponent="span" className="ml-1">{item.underlyingProtocol.toUpperCase()}</Text>
</Grid.Col>
<Grid.Col width={2}>
<Text size="h4" align="center" className="mb-0">{`${numeral(coverage.netAdjustedAPR).format('0.00')}%`}</Text>
</Grid.Col>
<Grid.Col width={2}>
<Text align="center">
{`${numeral(coverage.pTokenTotalDepositUsd).format('[=10=],0a')}`}
</Text>
<Text align="center" size="sm" muted>
{`${numeral(parseFloat(ethers.utils.formatUnits(coverage.pTokenTotalDepositTokens,item.underlyingTokenDecimals))).format('0,0a')} ${item.underlyingTokenSymbol.toUpperCase()}`}
</Text>
</Grid.Col>
<Grid.Col width={3} className="text-center">
<Tag.List>
<Tag rounded color="purple">{item.riskTag}</Tag>
</Tag.List>
</Grid.Col>
</Grid.Row>
</Card.Body>
</AccordionItemButton>
</AccordionItemHeading>
<AccordionItemPanel>
<ProtektHoldingSection
item={item}
tokenPrices={tokenPrices}
web3Context={web3Context}
gasPrice={gasPrice}
contracts={contracts}
coverage={coverage}
claimsManager={claimsManager}
accountBalances={accountBalances}
onRequery={()=>{
console.log('forcing update')
setRequery(prevState=>prevState + 1)
}}
actionCount={requery}
key={accountBalances}
/>
<Card.Body>
<Grid.Row>
<Grid.Col width={6}>
<h5 className="m-0 text-muted">{`COST`}</h5>
<p>{`${numeral(coverage.coverageFeeAPR).format('0.00')}% for ${coverage.coverageRatioDisplay} coverage`}</p>
<h5 className="m-0 text-muted">{`BACKED BY`}</h5>
<p>{`${item.backedByDisplay}`}</p>
</Grid.Col>
<Grid.Col width={6}>
<h5 className="m-0 text-muted">{`CLAIMS`}</h5>
<p>{`${item.claimsManagerDisplay}`}</p>
</Grid.Col>
</Grid.Row>
<Grid.Row>
<Grid.Col width={12}>
<h5 className="m-0 text-muted">{`COVERAGE FOR`}</h5>
<p>{`${item.coverageDisplay}`}</p>
</Grid.Col>
</Grid.Row>
</Card.Body>
{ !web3Context.ready ?
(<Card.Body><Text className="text-center font-italic">Connect Wallet Above<span role="img"></span></Text></Card.Body>) :
!accountBalances.ready ? <Card.Body><Dimmer active loader /></Card.Body> :
accountBalances[item.pTokenSymbol]["token"] === "0" ?
renderDepositCard() :
(<div></div>)
}
</AccordionItemPanel>
</Card>
</AccordionItem>
)
}
/** @component */
export default ProtektDepositCard;
非常感谢您的帮助/反馈。
更新
感谢您到目前为止的评论 - 我已经尝试在 useInterval 函数中增加一个基本计数器,但 UI 仍然没有更新相关状态:
function ProtektDepositCard({
children,
item,
lendingMarketMetrics,
tokenPrices,
}: Props): React.Node {
const [counter, setCounter] = useState(0)
useInterval(async () => {
(async function(){
/* other logic */
setCounter(counter+1)
})();
}, 5000)
console.log(`logging counter: ${counter}`)
return (
/* Other logic */
<div>counter: ${counter}</div>
/* Other logic */
)
/** @component */
export default ProtektDepositCard;
最小化的示例,但似乎仍然存在状态错误,状态每 5 秒正确记录一次更新计数器值,但它没有反映在 UI。
很遗憾,您正在使用的库 react-accessible-accordion
中似乎存在错误:
https://github.com/springload/react-accessible-accordion/issues/305
如果你把计数器放在手风琴的外面,你会看到它愉快地更新。或者,如果您切换手风琴,它也会更新!
所以我有一个 React 组件,它会每隔一段时间调用一个函数来获取帐户余额。组件的第一次加载从加载中成功更新,未准备就绪并提取用户帐户余额。
完成交易并在下一次账户余额轮询时,账户余额会在状态和日志中更新为正确的值,但不会在组件 UI(或任何子组件)上更新。我还尝试提取其中一个变量,如下所示为 pcDaiValue。这也会在第一次加载和第一次获取账户余额时更新,但是不会进一步更新,例如在交易之后。状态确实会更新并记录,但是 UI 不会更新以反映此状态。
我最初认为这是之前 post 中的子组件问题,但现在我意识到这是父组件的状态未更新。
如果您查看 pcDaiValue 状态 - 它将在状态而不是 UI 中更新。想知道一个可能的解决方案。
如有任何帮助,我们将不胜感激
下面的代码删除了不相关的部分:
function ProtektDepositCard({
children,
item,
lendingMarketMetrics,
tokenPrices,
}: Props): React.Node {
const [accountBalances, setAccountBalances] = useState({ready:false})
const [pcDaiValue, setPCDaiValue] = useState(0)
useInterval(async () => {
(async function(){
const newAccountBalances = await GetAccountBalances(
web3Context.address,
tokenPrices,
contracts,
[item.underlyingTokenSymbol, item.pTokenSymbol, item.reserveTokenSymbol, item.shieldTokenSymbol, item.coreTokenSymbol],
[item.underlyingTokenDecimals, item.pTokenDecimals, item.reserveTokenDecimals, item.shieldTokenDecimals, item.coreTokenDecimals],
[item.pTokenAddress, item.pTokenAddress, item.shieldTokenAddress, item.shieldTokenAddress, item.pTokenAddress],
[null, item.underlyingTokenSymbol, null, item.reserveTokenSymbol, null]
)
console.log('retrieved account balances')
console.log(newAccountBalances)
console.log('retrieved pcdai')
console.log(pcDaiValue)
if(newAccountBalances['pcdai']){
const pTokenValue = newAccountBalances['pcdai']['token']
setPCDaiValue(pTokenValue)
}
setAccountBalances({...newAccountBalances})
})();
}, 5000)
console.log('logging account balances')
console.log(accountBalances)
return ( (coverage.loading) ? <Card><Card.Body><Dimmer active loader /></Card.Body></Card> :
<AccordionItem
key={accountBalances}
>
<div>PCDAI VALUE: {String(pcDaiValue)}</div>
<Card className="mb-1">
<AccordionItemHeading>
<AccordionItemButton>
<Card.Body>
<Grid.Row alignItems="center" justifyContent="center">
<Grid.Col width={2}>
<Avatar
imageURL={`assets/${item.coreTokenLogo}.png`}
style={{"verticalAlign":"middle"}}
/>
<Text size="h4" align="center" RootComponent="span" className="ml-2">{item.coreToken.toUpperCase()}</Text>
</Grid.Col>
<Grid.Col width={3}>
<Avatar
imageURL={`assets/${item.protocolLogo}.png`}
style={{"verticalAlign":"middle"}}
size="lg"
/>
<Text size="h4" align="center" RootComponent="span" className="ml-1">{item.underlyingProtocol.toUpperCase()}</Text>
</Grid.Col>
<Grid.Col width={2}>
<Text size="h4" align="center" className="mb-0">{`${numeral(coverage.netAdjustedAPR).format('0.00')}%`}</Text>
</Grid.Col>
<Grid.Col width={2}>
<Text align="center">
{`${numeral(coverage.pTokenTotalDepositUsd).format('[=10=],0a')}`}
</Text>
<Text align="center" size="sm" muted>
{`${numeral(parseFloat(ethers.utils.formatUnits(coverage.pTokenTotalDepositTokens,item.underlyingTokenDecimals))).format('0,0a')} ${item.underlyingTokenSymbol.toUpperCase()}`}
</Text>
</Grid.Col>
<Grid.Col width={3} className="text-center">
<Tag.List>
<Tag rounded color="purple">{item.riskTag}</Tag>
</Tag.List>
</Grid.Col>
</Grid.Row>
</Card.Body>
</AccordionItemButton>
</AccordionItemHeading>
<AccordionItemPanel>
<ProtektHoldingSection
item={item}
tokenPrices={tokenPrices}
web3Context={web3Context}
gasPrice={gasPrice}
contracts={contracts}
coverage={coverage}
claimsManager={claimsManager}
accountBalances={accountBalances}
onRequery={()=>{
console.log('forcing update')
setRequery(prevState=>prevState + 1)
}}
actionCount={requery}
key={accountBalances}
/>
<Card.Body>
<Grid.Row>
<Grid.Col width={6}>
<h5 className="m-0 text-muted">{`COST`}</h5>
<p>{`${numeral(coverage.coverageFeeAPR).format('0.00')}% for ${coverage.coverageRatioDisplay} coverage`}</p>
<h5 className="m-0 text-muted">{`BACKED BY`}</h5>
<p>{`${item.backedByDisplay}`}</p>
</Grid.Col>
<Grid.Col width={6}>
<h5 className="m-0 text-muted">{`CLAIMS`}</h5>
<p>{`${item.claimsManagerDisplay}`}</p>
</Grid.Col>
</Grid.Row>
<Grid.Row>
<Grid.Col width={12}>
<h5 className="m-0 text-muted">{`COVERAGE FOR`}</h5>
<p>{`${item.coverageDisplay}`}</p>
</Grid.Col>
</Grid.Row>
</Card.Body>
{ !web3Context.ready ?
(<Card.Body><Text className="text-center font-italic">Connect Wallet Above<span role="img"></span></Text></Card.Body>) :
!accountBalances.ready ? <Card.Body><Dimmer active loader /></Card.Body> :
accountBalances[item.pTokenSymbol]["token"] === "0" ?
renderDepositCard() :
(<div></div>)
}
</AccordionItemPanel>
</Card>
</AccordionItem>
)
}
/** @component */
export default ProtektDepositCard;
非常感谢您的帮助/反馈。
更新
感谢您到目前为止的评论 - 我已经尝试在 useInterval 函数中增加一个基本计数器,但 UI 仍然没有更新相关状态:
function ProtektDepositCard({
children,
item,
lendingMarketMetrics,
tokenPrices,
}: Props): React.Node {
const [counter, setCounter] = useState(0)
useInterval(async () => {
(async function(){
/* other logic */
setCounter(counter+1)
})();
}, 5000)
console.log(`logging counter: ${counter}`)
return (
/* Other logic */
<div>counter: ${counter}</div>
/* Other logic */
)
/** @component */
export default ProtektDepositCard;
最小化的示例,但似乎仍然存在状态错误,状态每 5 秒正确记录一次更新计数器值,但它没有反映在 UI。
很遗憾,您正在使用的库 react-accessible-accordion
中似乎存在错误:
https://github.com/springload/react-accessible-accordion/issues/305
如果你把计数器放在手风琴的外面,你会看到它愉快地更新。或者,如果您切换手风琴,它也会更新!