【发布时间】:2021-05-27 00:26:18
【问题描述】:
所以我有一个反应组件,它会每隔一段时间调用一个函数来获取帐户的余额。组件的第一次加载成功地从加载更新到未准备就绪并拉入用户帐户余额。
在完成交易和下一次账户余额轮询时,账户余额会在状态中更新并使用正确的值记录,但不会在组件 UI(或任何子组件)上更新。我还尝试提取其中一个变量,如下所示为 pcDaiValue。这也会在首次加载和首次获取账户余额时更新,但不会进一步更新,例如在交易之后。状态会更新并记录,但 UI 不会更新以反映此状态。
我最初认为这是上一篇文章中的子组件问题,但现在我意识到这是父组件的状态未更新。
如果您查看 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('$0,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;
非常感谢您的任何帮助/反馈。
更新
到目前为止,感谢 cmets - 我已经尝试在 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 中。
【问题讨论】:
-
如果
pcDaiValue更新并且您确认通过将其记录在任何处理程序或效果之外的组件内部,则 UI 不可能不更新。除非在此处显示的代码之外有一些奇怪的记忆。 -
是的,这就是为什么我也很困惑...... UI 不会更新,但两个日志都会更新(accountBalances 和单个 pcDAI 显示正确的值)。关于其他任何地方可能导致这种情况的任何进一步想法?
-
此处提供完整的 repo link - 有问题的组件位于 ProtektDepositCard -> ProtektDepositCard
-
pcDaiValue的控制台日志是在一个效果里面。您能否直接在组件return之前记录它并确认它被调用并具有不同的值? -
已确认将其移出效果 - 记录新值但 UI 未更新以反映新状态 - 也更新了 github 存储库以供参考
标签: reactjs react-hooks use-effect use-state