useState() hook value 1 step behind, already using useEffect()

Viewed 37

I have an list of values pairList that I'm trying to access with an id from the click event. There is a popup list that doesn't even display if pairList is not populated. I make the popup show up with a listTrigger hook. When I click a pair, I expect to have the currPair set which depends on pairList being populated but it prints as empty.

I should only ever be able to access the handler for changing currPair if pairList is populated, since it calls setListTrigger only after pairList is populated in useEffect(). It shows it as populated in the useEffect() function but it prints empty in handlePairChange(). Here is a simplified version of the code. To my understanding It shouldn't even be able to activate handlePairChange() unless pairList is populated.

parent.tsx

const [listTrigger, setListTrigger] = useState<boolean>(false)
const [currPair, setCurrPair] = useState<PairProps>(intialPair)
const [pairList, setPairList] = useState<PairProps[]>([])
const pairListProps: PairListProps = {trigger: listTrigger, setTrigger: setListTrigger, pairs: pairList}

 //async function that gets data from server
 function handleListTrigger(e: React.MouseEvent) {
    var client: Client = new Client()
    client.getPairList().then(result => {
        var pairs = result[1].pools
        for (let pair of pairs) {
            pair.setPair = handlePairChange
        }
        setPairList(pairs)
    })
}

React.useEffect(() => {
    if(pairList.length !== 0) {
        console.log(pairList)
        setListTrigger(true)
    }
}, [pairList])

function handlePairChange(e: React.MouseEvent) {
    let selectedPairID = e.currentTarget.getAttribute("id")
    console.log(selectedPairID)          //prints correct id
    console.log(pairList)                //prints empty list first time
    for (let pair of pairList) {
        if (pair.id === selectedPairID) {
            console.log("SET CURRENT PAIR TO", pair)
            setCurrPair(pair)
        }
    }
}

return(
    <PairList props={pairListProps}/>
)

PairList.tsx

export interface PairListProps {
  trigger: boolean
  setTrigger: React.Dispatch<React.SetStateAction<boolean>>
  pairs: PairProps[]
}

export interface PairProps {
  id: string
  tokenA: Token
  tokenB: Token
  exchangeRate: number
  setPair: React.MouseEventHandler<HTMLTableRowElement>
}

export interface Token {
  name: string
  amountInPool: number
}

export default function PairList({props}: {props: PairListProps}) {
  if (props.trigger === true) {
    return (
      <div className="pairlist">
        <div className="pairlist-inner">
          <button className="close-btn" onClick={() => props.setTrigger(false)}>
            Close
          </button>
          <table>
            <tbody>
              {props.pairs.map(pair => <Pairs key={pair.id} pair={pair}/>)}
            </tbody>
          </table>
        </div>
      </div>
    )
  }
  else {
    return <></>
  }
}

function Pairs({pair}: {pair: PairProps}) {
  return (
    <tr id={pair.id} onClick={pair.setPair}>
      <button>{pair.tokenA.name}/{pair.tokenB.name}</button>
    </tr>
  )
}
0 Answers
Related