【问题标题】:setState does not change/rerendersetState 不会改变/重新渲染
【发布时间】:2022-01-06 11:42:41
【问题描述】:

我使用给定的 JS、React 和 CoreUI4 React 技术栈开发应用程序的前端原型。 我来自 Python 背景,在 Web 开发和给定的技术堆栈方面没有太多经验。当我不得不开始使用钩子时,这一点变得很明显。

问题

我真的不明白为什么它不更新我的usestate 和/或不渲染。我需要一个条件渲染,我也使用setState

我尝试过:

  • 从我的主应用程序传递一个更大的状态,一旦我开始条件逻辑(挂钩规则)就不起作用
  • 实现 useEffect 在这里和其他变体中,没有改变任何东西。
  • 还有很多其他我不记得也没有用的东西。

当我单击其中一个按钮时,控制台会为我提供以下信息:

test1.js:21 useEffect //3 times from first render
test1.js:33 clicked (3) ['Some other Stuff available', '', 'cbutton']
test1.js:34 _testSubL  (3) ['Some other Stuff available', '', 'cbutton']
test1.js:46 tmpState:  (3) ['Some other Stuff available', 'pass', 'cbutton']
test1.js:47 btUS:  (3) ['Some other Stuff available', '', 'cbutton']
test1.js:21 useEffect

在第二次及以下点击时:

test1.js:33 clicked (3) ['Some other Stuff available', 'pass', 'cbutton']
test1.js:34 _testSubL  (3) ['Some other Stuff available', '', 'cbutton']
test1.js:46 tmpState:  (3) ['Some other Stuff available', 'pass', 'cbutton']
test1.js:47 btUS:  (3) ['Some other Stuff available', 'pass', 'cbutton']
test1.js:21 useEffect

我创建了一个较小的测试版本,其中所有内容都在一个文件中,并且不导入数据或任何其他自定义函数。

import React, { lazy, useState, useEffect } from 'react'

import { CButton, CCol, CRow, CContainer } from '@coreui/react'

var tmpState = []
var inp1 = {
  id: 2,
  TestPhase: 'TestPhase',
  results: [
    [['File Input', 'some Doc', 'file']],
    [['Some Stuff available', 'pass', 'cbutton']],
    [['Some other Stuff available', '', 'cbutton']],
  ],
}.results
const ChangeButton = (_testSubL) => {
  const [btUS, setbtUS] = useState(_testSubL)

  useEffect(() => {
    console.log('useEffect')
  }, [btUS])

  //console.log('begin from: ', _testSubL)
  return (
    <>
      <CButton
        className="mx-1"
        color="secondary"
        shape="rounded"
        size="sm"
        onClick={() => {
          console.log('clicked', btUS)
          console.log('_testSubL ', _testSubL)
          tmpState = btUS
          if (_testSubL[2] == 'cbutton' && _testSubL[1] == 'pass') {
            tmpState = [_testSubL[0], 'fail', _testSubL[2]]
          } else if (_testSubL[2] == 'cbutton' && _testSubL[1] == 'fail') {
            tmpState = [_testSubL[0], 'pass', _testSubL[2]]
          } else if (_testSubL[2] == 'cbutton' && _testSubL[1] == '') {
            tmpState = [_testSubL[0], 'pass', _testSubL[2]]
          } else {
            //pass
          }
          setbtUS(tmpState)
          console.log('tmpState: ', tmpState)
          console.log('btUS: ', btUS)
        }}
      >
        Change
      </CButton>
    </>
  )
}
const TestMain = () => {
  return (
    <>
      <CContainer>
        <h3>Just some Test Page</h3>
        {inp1.map((_subl) => (
          <CRow className="justify-content-center pt-1" key={_subl[0][0]}>
            <CCol md="2">Some Icon: {_subl[0][1]}</CCol>
            <CCol md="3">{_subl[0][0]}</CCol>
            <CCol md="3">{ChangeButton(_subl[0])}</CCol>
          </CRow>
        ))}
      </CContainer>
    </>
  )
}

export default TestMain

感谢阅读,我希望这是可以理解的,因为这是我的第一篇文章

【问题讨论】:

  • 您有什么证据表明调用 setbtUS() 不会重新呈现?当你点击按钮时会发生什么?您是否尝试过只执行 alert()console.log() 的更简单的 onClick 回调?
  • 你永远不会使用btUS 来实际渲染任何东西。所以你不能在应用程序中说 setState 永远不会被调用。另外,为什么btUS 是一个包含三个不同项目的数组。数组应该用于类似项目的列表。在这种情况下,您应该使用对象{message: "Some stuff", status: "pass", control: "cbutton"}。注意这更有意义,因为你给每个字符串一个名字。
  • @Code-Apprentice 非常感谢,这个反馈真的很有帮助,我已经将数组更改为对象。但我认为,尤其是您的第二条评论是我的主要问题。我需要在 TestMain 函数中更改状态 btUS。我应该在哪里初始化useState?我可以在TestMain 中这样做并在参数中传递它吗?但是我可能会在.map() 中遇到setState 的问题,不是吗?
  • 我不太明白你在问什么。我认为这里的问题是你正在挖掘你的应用程序的“如何”,而我仍然不清楚“什么”。我的意思是我不明白你的应用程序应该做什么,比如页面上显示的 UI 元素以及用户与它们交互时会发生什么。在弄清楚如何在代码中实际实现它之前,清楚地了解“什么”是很重要的。
  • 感谢您继续关注@Code-Apprentice。按下按钮,我想更改您调用的值 statustmpState[1]。在我的完整应用程序中,有另一个组件从这个值返回一个图标。实际上我刚刚设法解决了这个问题,但我不明白为什么......我现在不做setbtUS(tmpState),而是做setbtUS([...tmpState]),它可以工作。但我不明白“tmpState”和“[...tmpState]”之间的区别。你能帮我理解一下吗?

标签: reactjs react-hooks use-state core-ui


【解决方案1】:

您可以在该特定状态变量的 useeffect 挂钩中获取更新的值,因为它不会立即更新自身。并在获得新价值后将您的逻辑放在这里。

  useEffect(() => {
    console.log('useEffect btUS', btUS)
  }, [btUS])

【讨论】:

  • 感谢检查和可视化的好方法
【解决方案2】:

如果你需要查看更新状态的console.log,你可以让你的回调异步等待console.log。

async () => {
  ...
  setbtUS(tmpState);
  await console.log('tmpState: ', tmpState);
  await console.log('btUS: ', btUS);
}

【讨论】:

    【解决方案3】:

    您不会立即看到新状态,因为setState 以异步方式工作,因此它不会立即自我更新。由于这个原因,您第一次看到它不会在第一次立即更新。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-20
    • 2019-01-24
    • 2015-06-10
    • 2016-09-09
    • 2018-02-27
    • 2019-09-26
    • 2019-12-13
    • 1970-01-01
    相关资源
    最近更新 更多