1

I work on a frontend-prototype of an app with a given tech stack of JS, React and CoreUI4 React. I come from a Python background and don't have that much experience in web development and my given tech stack. This became evident when I had to start to work with hooks.

Problem

I don't really understand why it is not updating my usestate and/or doesn't render. I need a conditional render where I also use setState.

I tried to:

  • pass one bigger state from my main app, didn't work once I started conditional logic (Rule of Hooks)
  • implement useEffect as seen here and in other variations, didn't change anything.
  • and a lot of other stuff that I don't recall and didn't work.

When I click one of the Buttons the console gives me this info:

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

and on the second and following clicks:

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

I create a smaller test version where everything is in one file and doesn't import data or any other custom functions.

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

Thanks for reading, I hope this is understandable, since it is my first post

ReinerMal
  • 11
  • 2
  • What evidence do you have that calling `setbtUS()` doesn't re-render? What happens when you click on the button? Have you tried with a simpler `onClick` callback that just does an `alert()` or `console.log()`? – Code-Apprentice Nov 29 '21 at 16:22
  • You never use `btUS` to actually render anything. So you can't tell in the app that setState is never called. Also, why is `btUS` an array with three different items. Arrays should be used for lists of similar items. In this case you should use an object `{message: "Some stuff", status: "pass", control: "cbutton"}`. Notice how this is more meaningful because you give each string a name. – Code-Apprentice Nov 29 '21 at 16:26
  • @Code-Apprentice thanks a lot, this feedback is really helpful and I already changed the arrays to objects. But especially your second comment is my main problem, I think. I need the changes to state `btUS` in my `TestMain` function. Where should I initialize the `useState`? Can I do so in the `TestMain` and pass it over in the parameters? But then I'll probably have problems with `setState` inside the `.map()`, won't I? – ReinerMal Nov 30 '21 at 09:22
  • I don't really understand what you are asking. I think the problem here is that you are digging into the "how" of your app and I'm still unclear about the "what". I mean that I don't understand what your app is supposed to do, as in what UI elements are showing on the page and what happens when the user interacts with them. It is important to have a clear idea of the "what" before figuring how to actually implement it in code. – Code-Apprentice Nov 30 '21 at 16:41
  • Thanks for staying on it @Code-Apprentice. With the push of the button I want to change my the value you called `status` or `tmpState[1]`. In my full app there is another component that returns an icon from this value. I actually managed to fix this issue just now, but I don't understand why... Instead of doing `setbtUS(tmpState)` I now do `setbtUS([...tmpState])` and it works. But I don't understand the difference between 'tmpState' and '[...tmpState]'. Could you help me with understanding this? – ReinerMal Dec 03 '21 at 13:39

3 Answers3

3

You don't see immediately the new state because setState works in an asynchronous way, so it doesn't update itself immediately. For this reason the first time you don't see it updated immediately on the first time.

Giacomo
  • 344
  • 3
  • 11
  • Thanks a lot, that was the first part of my problem and I guessed it to be so from [React Hooks: updating state using useState does not update the state immediately](https://stackoverflow.com/questions/59925451/react-hooks-updating-state-using-usestate-does-not-update-the-state-immediately) and some other posts I read, should have specified that. – ReinerMal Nov 30 '21 at 09:26
0

If you need to see the console.log of updated state, you can make your callback asynchronous and await console.log.

async () => {
  ...
  setbtUS(tmpState);
  await console.log('tmpState: ', tmpState);
  await console.log('btUS: ', btUS);
}
bgcodes
  • 248
  • 2
  • 12
0

You can get an updated value here in useeffect hook of that particular state variable as it doesn't update itself immediately. And put your logic here after getting new value.

  useEffect(() => {
    console.log('useEffect btUS', btUS)
  }, [btUS])
Nensi Kasundra
  • 1,980
  • 6
  • 21
  • 34