【问题标题】:React State Update Working for First State Update but Failing on any further updates反应状态更新为第一个状态更新工作,但在任何进一步的更新上都失败了
【发布时间】: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


【解决方案1】:

很遗憾,您正在使用的库 react-accessible-accordion 中似乎存在错误:

https://github.com/springload/react-accessible-accordion/issues/305

如果你把计数器放在手风琴外面,你会看到它愉快地更新。或者,如果您切换手风琴,它也会更新!

【讨论】:

  • 非常感谢您解决这个问题!
猜你喜欢
  • 2021-06-02
  • 2017-07-15
  • 2021-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多