【问题标题】:Why can't my function read the actual value of my component's state?为什么我的函数不能读取组件状态的实际值?
【发布时间】:2023-04-10 21:05:01
【问题描述】:

对于一个学校项目,我的小组正在构建一个表,该表通过数据库调用填充了城市数据。 表格组件的骨架是这样的:

import React, { useState } from 'react' 

function Table(props) {
  const [ cities, setCities ] = useState([])
  const [ pageNum, setPageNum ] = useState(0)

  useEffect(()=> { // this sets up the listener for the infinite scroll
    document.querySelector(".TableComponent").onscroll = () => {
      if (Math.ceil(table.scrollHeight - table.scrollTop) === table.clientHeight) showMoreRows()
    }
    //initial fetch
    fetchData(0)
  },[])

  async function showMoreRows() {
    console.log("Show more rows!")
    await fetchData(pageNum)
  }

  async function fetchData(page) {
    // some code, describing fetching
    // EDIT2 start
    console.log(pageNum)
    // EDIT2 end
    const jsonResponse = await {}// THE RESPONSE FROM THE FETCH
    if(page) {
      setCities([...cities, ...jsonResponse])
      console.log("page is true", page)
      setPageNum(pageNum + 1)
    } else {
      console.log("page is false", page) // this always runs and prints "page is false 0"
      setCities([...cities, ...jsonResponse])
      setPageNum(1)
    }
  }


  return <div className="TableComponent"> { pageNum } 
           <!-- The rest of the component --> 
         </div>
}

该表格具有“无限滚动”功能,因此当您滚动到页面底部时,它会打印"Show more rows!" 并运行fetchData(pageNum) 以获取更多数据。此时,在初始提取之后,pageNum-变量应该是 1 或更大,但由于某种原因,该函数的行为就像是 0。我将 pageNum-变量显示在 JSX 中,然后我可以看到它是1,但是当我运行它时它仍然会打印出"page is false 0"

当我尝试用谷歌搜索该问题时,似乎唯一类似的事情可能是我在使用 setPageNum 之后(重绘之前)过早地尝试读取 useState 变量,但就这里而言,情况并非如此我可以看到。我在两次尝试之间给了它足够的时间,它总是说pageNum 为零。

任何关于我做错了什么的想法,以及这有什么意义?

感谢您的帮助!

编辑:刚刚尝试了我写的代码,它似乎工作 - 但是我拥有的完整代码不起作用。任何人都对与此相关的问题有任何想法,即使上面的代码可能有效?

EDIT2:我在fetchData 函数中添加了一个console.log(pageNum),并进行了一些测试,似乎我在useState(VALUE) 中放入的初始值就是正在打印的内容。这对我来说 NO 有意义。 帮助。

EDIT3:添加了等待,在实际代码中已经有了它

EDIT4:我已经尝试了一段时间,但意识到当我使用 react 时,我可以将我拥有的滚动侦听器移动到 JSX 区域,然后它工作了——出于某种原因。现在可以了。无法真正将任何答案标记为正确答案,但问题在一定程度上得到了解决。

感谢所有试图提供帮助的人,非常感谢。

【问题讨论】:

  • 您能否创建一个沙箱或其他东西来重现问题,以便我们检查代码以及它是如何工作的?
  • 看起来fetchData 内的条件中的条件正在将您的页面0 处理为false,您应该检查它是否大于或等于0,因为您正在检查数量如果页面存在,则页面不存在

标签: javascript reactjs q


【解决方案1】:

您的过时问题正在发生,因为 React 不知道您对组件状态的依赖。

例如,useEffect 确保每次滚动都会调用初始渲染范围内的 showMoreRows 值。 showMoreRows 的这个副本引用了 pageNum 的初始值,但该值与函数一起在 closure 中“冻结”,并且在组件状态发生变化时不会改变。因此滚动监听将无法工作,因为它需要知道pageNum 的当前状态。

您可以通过使用 callbacks 来“挂钩”showMoreRowsfetchData 并声明它们对组件状态的依赖性来解决问题。然后,您必须声明 useEffect 对这些回调的依赖,并使用 clean-up function 来处理多次调用的效果。

它看起来像这样(我没有尝试运行代码):

import React, { useState } from 'react' 

function Table(props) {
  const [ cities, setCities ] = useState([])
  const [ pageNum, setPageNum ] = useState(0)

  useEffect(()=> { 
    // Run this only once by not declaring any dependencies
    fetchData(0)
  }, [])

  useEffect(()=> {
    // This will run whenever showMoreRows changes.

    const onScroll = () => {
      if (Math.ceil(table.scrollHeight - table.scrollTop) === table.clientHeight) showMoreRows()
    };

    document.querySelector(".TableComponent").onscroll = onScroll;

    // Clean-up
    return () => document.querySelector(".TableComponent").onscroll = null;
  }, [showMoreRows])

  const showMoreRows = React.useCallback(async function () {
    console.log("Show more rows!")
    await fetchData(pageNum)
  }, [fetchData, pageNum]);

  const fetchData = React.useCallback(async function (page) {
    // some code, describing fetching
    // EDIT2 start
    console.log(pageNum)
    // EDIT2 end
    const jsonResponse = await {}// THE RESPONSE FROM THE FETCH
    if(page) {
      setCities([...cities, ...jsonResponse])
      console.log("page is true", page)
      setPageNum(pageNum + 1)
    } else {
      console.log("page is false", page) // this always runs and prints "page is false 0"
      setCities([...cities, ...jsonResponse])
      setPageNum(1)
     }
  }, [setCities, cities, setPageNum, pageNum]);

  return <div className="TableComponent"> { pageNum } 
           <!-- The rest of the component --> 
         </div>
}

【讨论】:

【解决方案2】:

这可能无法完全解决问题(如果没有更多上下文很难判断),但 useEffect 运行 every render,所以像“初始”fetchData(0) 这样的东西将运行每个更新,这可能会给你每次在fetchData 中的条件中都来自page = 0

【讨论】:

  • 这是一个合理的猜测,但是 useEffect 末尾的空数组应该使 useEffect 更类似于 componentDidMount,因为它应该只运行一次,就在挂载之后。如果我错了,请纠正我。
  • 我还加了一张支票:if(citites.length === 0) fetchData(0),但这并没有改变任何东西,所以我认为问题不在于这个。
【解决方案3】:

没有更多上下文很难说,但我有一个猜测。 尝试使用

setCities(value => [...value, ...jsonResponse])

而不是

setCities([...cities, ...jsonResponse])

还要确保您使用 await 来解决以下请求的承诺:

const jsonResponse = await ...

您可以通过控制台记录它以检查它们是否未挂起,如果它是嵌套对象,您是否获得了正确的属性。

【讨论】:

  • 在我的实际代码中,我对fetchresponse.json() 都使用了等待,但公平地指出,因为我没有将它放在骨架代码中。至于setCities-function-parameter,我试过了,但似乎cities在函数中被读取为[],而不是任何长度,所以问题是函数似乎无法读取州。
猜你喜欢
  • 2022-01-07
  • 2012-02-26
  • 2017-12-28
  • 1970-01-01
  • 2019-10-19
  • 2020-07-11
  • 1970-01-01
  • 2023-02-06
  • 2021-05-26
相关资源
最近更新 更多