为什么我的 React useState 钩子常量的状态丢失了?

问题描述 投票:0回答:1

我正在尝试在 React 中构建一个信息面板,显示在线社区的三项最新活动。主要是最新注册社区的人。

我目前有一个最新 30 个注册的列表,作为 JSX 组件数组从 API 调用加载到 dataArr 常量中。然后,我有一个进一步的 useEffect,它是由 dataArr 常量的更新触发的,该常量将 dataArr 中的最后 3 项保存到进一步的数组常量调用结果中。然后,它会以包含 3 项的列表的形式显示在屏幕上。

这工作正常,但我的下一步是将 dataArr 修剪 1 个项目(数组中的最后一个项目),以便显示自动更新以丢失 3 列表中的最后一个项目并获得一个新项目。然后我将添加一个漂亮的动画过渡效果,以便用户可以看到正在发生的事情。

我创建了一个测试来确保逻辑有效 - testAction - 这是从添加到 JSX 元素之一的 onClick 操作调用的,这就是我遇到麻烦的地方。 testAction 函数中的 dataArr 常量显示为空。它已丢失数据。

我添加了一个新的返回页面,该页面具有硬编码的 JSX 元素,而不是从数组写入的元素,并且当我从静态返回调用 testAction 函数时,dataArr 中的值仍然存在。然而,当从实际返回(从包含动态生成的基于数组的 JSX 的“结果”常量生成的返回)调用它时,dataArr 变量始终为空。

我最终想使用 setInterval() 以 10 秒的间隔运行 testAction 代码,当我再次尝试从 setInterval() 执行代码时,dataArr 常量为空。

是什么导致 dataArr 常量丢失数据?跟我把 JSX 代码写进数组有关系吗?

如有任何建议,我们将不胜感激。

import React, { createRef, forwardRef, useEffect, useState } from 'react'
import { Link, withRouter } from 'react-router-dom'
import { withAuth } from '../../AuthContext'
import {
  Title,
  PrimaryOutlineButton,
  SubtitleOpen,
} from '../../Utils/CustomClasses'
import styled from 'styled-components'

const LatestActivityWrapper = styled.div`
  margin: 0 0 40px 0;
`

const LatestActivityTitle = styled(Title)`
  font-size: 18px !important;
`

const ActivityName = styled.div`
  display: flex;
  gap: 5px;
  flex-wrap: nowrap;
`

const BreakSub = styled(SubtitleOpen)`
  display: flex;
  overflow-wrap: anywhere;
  font-color: #941e15 !important;
  font-family: 'Open Sans', sans-serif;
  font-size: 18px;
  font-weight: 400;
  margin: 4px 0 0 0;
`

const BreakSubActivity = styled(BreakSub)`
  width: 125px;
  font-weight: 300;
  font-size: 16px;

  b {
    font-weight: 600;
  }
`

const BreakSubActivityRight = styled(BreakSubActivity)`
  font-size: 16px;
  width: -webkit-fill-available;
`

const ActivityText = styled(SubtitleOpen)`
  font-family: 'Open Sans', sans-serif;
  font-size: 16px;
  font-weight: 300;
  margin: 8px 0 0;
`

const LatestActivity = () => {
  const [dataArr, setDataArr] = useState([])
  const [results, setResults] = useState('')
  const [test, setTest] = useState('')

  useEffect(() => {
    axios
      .get(`/api/XXXXXXXXXXXXXXX/latestactivity`)
      .then((response) => {
        setTest('test text')
        setDataArr(
          response.data.map((d, index) => {
            return (
              <LatestActivityComponent
                ref={createRef()}
                key={index}
                u={d.forename}
                country={d.country.nicename}
                activityType={'SIGNUP'}
                color={'#3DBD7E'}
                activityText={
                  d.forename + ' signed up from ' + d.country.nicename
                }
              />
            )
          })
        )
      })
      .catch((err) => {
        console.log('Error getting latest featured activity: ', err)
      })
  }, [])

  useEffect(() => {
    console.log('dataArr: ' + JSON.stringify(dataArr))
    setResults(dataArr.slice(dataArr.length - 3, dataArr.length))
  }, [dataArr])

  const testAction = () => {
    console.log('testAction....')
    console.log('test: ' + test)
    console.log('dataArr: ' + dataArr)
    console.log('test: ' + test)
    console.log('dataArr.length: ' + dataArr.length)

    const newData = dataArr.pop()

    console.log('dataArr.length: ' + dataArr.length)
    console.log('dataArr: ' + dataArr)

    setDataArr(dataArr)
  }

  const LatestActivityComponent = forwardRef(
    ({ u, country, activityType, color, activityText }, ref) => {
      return (
        <LatestActivityWrapper ref={ref}>
          <LatestActivityTitle color={color} size="18px">
            {activityType}
          </LatestActivityTitle>
          <ActivityName>
            <BreakSubActivity onClick={() => testAction()}>
              <b>Name:</b>
            </BreakSubActivity>
            <BreakSubActivityRight>{u}</BreakSubActivityRight>
          </ActivityName>
          <ActivityName>
            <BreakSubActivity>
              <b>Location:</b>
            </BreakSubActivity>
            <BreakSubActivityRight>{country}</BreakSubActivityRight>
          </ActivityName>
          <ActivityText>{activityText}</ActivityText>
        </LatestActivityWrapper>
      )
    }
  )

  if (!results || test == '') {
    return (
      <div className="card-body text-center">
        <div
          className="spinner-border homestays-spinner"
          style={{ margin: '100px auto 100px', opacity: '0.3' }}
          role="status"
        ></div>
      </div>
    )
  }
  // The testAction function does not work from here
  //return results

  // The testAction function works from here
  return (
    <BreakSubActivity onClick={() => testAction()}>
      aaa - {test}
    </BreakSubActivity>
  )
}

export default withRouter(withAuth(LatestActivity))
reactjs react-hooks
1个回答
0
投票

dataArr.pop()
会改变 dataArr。可以用
slice(0, -1)
代替;它返回原始数组的副本,没有最后一个元素。

testAction
的最小版本可以如下所示:

const testAction = () => {
    setDataArr(prev => prev.slice(0, -1))
}
© www.soinside.com 2019 - 2024. All rights reserved.