【问题标题】:useEffect overriding the state instead of appending the values while making firestore callsuseEffect 在进行 firestore 调用时覆盖状态而不是附加值
【发布时间】:2020-11-22 05:06:47
【问题描述】:
const [data, setData] = useState([])
    
     const getDataFromFirebase = async () => {
         let response = await firestore.collection('someDatabase').get()
         response.forEach(item => setData([...data, item.data().name]))
         
     }
    
    useEffect(() => {
       getDataFromFirebase()
    },[])

数据被最新值覆盖,而不是将所有值添加到数组中。

【问题讨论】:

  • item.data() 是一个函数吗?
  • data 在 useEffect 中使用。请把它放在依赖数组中。虽然这可能会导致无限循环......

标签: javascript reactjs firebase google-cloud-firestore use-effect


【解决方案1】:

原因是添加项目所花费的时间非常少,这就是为什么在反映之前,它被覆盖了。您必须在 setData 中使用 prevState 。试试这个:

const [data, setData] = useState([])

const getDataFromFirebase = async () => {
let response = await firestore.collection('someDatabase').get()
response.forEach(item => setData(prevState => ([
    ...prevState, item.data().name])
  );
}
useEffect(() => {
  getDataFromFirebase()
  },[])

【讨论】:

    【解决方案2】:

    使用setData中的回调

    setData(prevState => ([
        ...prevState, item.data().name
    ]));
    

    【讨论】:

      【解决方案3】:
      let response = await firestore.collection('someDatabase').get()
      response.forEach(item => setData([...data, item.data().name]))
      

      我不熟悉firestore,但该承诺将被解决一次,您应该这样做:

      const dataToAdd = response.map(item => item.data().name)
      setData(prevState => ([...prevState, ...dataToAdd])
      

      每次调用 setData 时都会重新渲染组件,并且不应在同步循环中执行此操作。

      prevState 在这里是必需的,因为您正在使用异步函数。理论上,如果您不在其他任何地方更改状态,则在使用 dataToAdd 的解决方案后,它应该可以在没有它的情况下工作。

      【讨论】:

        【解决方案4】:

        尝试此触发 setState 一次,但在此之前构建数组:

        const [data, setData] = useState([])
            
         const getDataFromFirebase = async () => {
            let response = await firestore.collection('someDatabase').get()
            const d = response.map(item=> item.data().name)
            setData(d)  
          }
            
         useEffect(() => {
               getDataFromFirebase()
         },[])
        

        多次触发setData 会导致多次重新渲染,所以这里只触发一次。

        【讨论】:

        • 尝试过这种方式,但我将地图更改为 forEach 并且效果很好。但我想知道为什么我的早期版本不起作用
        • map 应该有返回值,foreach 不需要返回。以及为什么您以前的代码无法正常工作,因为反应更新状态是异步的,所以当您触发 setData([...data, item.data().name]) 时,可能还没有通过反应设置数据,为什么它仍然是空的
        • @adel OP 询问为什么没有附加数据,这个解决方案没有回答这个问题。上面的代码不会附加到现有的数据数组中。它只是覆盖它。
        • @phantomCode 哦,是的,你是对的,但是对于上面的代码,getDataFromFirebase 只触发了一个正在挂载的代码,默认状态是空数组,所以没有什么可以覆盖的。我们想触发附加到其他地方的状态,我们可以像这样使用setState回调: setData(currentState=>[...currenState,..d])
        【解决方案5】:

        在您下面的代码中,数据的值将始终为[],即使您稍后更改数据。

        const getDataFromFirebase = async () => {
                 let response = await firestore.collection('someDatabase').get()
                 response.forEach(item => setData([...data, item.data().name]))
                 
             }
        

        这就是文档所说的

        突变、订阅、计时器、日志记录和其他副作用是 不允许在功能组件主体内部(指 作为 React 的渲染阶段)。这样做会导致令人困惑的错误和 用户界面不一致。

        在每个循环中调用 setData 并不是一个好主意。一旦循环完成,填充一个数组并将其传递给setData

             const getDataFromFirebase = async () => {
                 let response = await firestore.collection('someDatabase').get();
                 let newData = [];
                 response.forEach(item => newData.push(item.data().name));
        
                 // now set the new data
                 setData(prevData=> ([...prevData, ...newData]));
                 
                 // or you can use Array.concat
                 // setData(prevData=> (prevData.concat(newData)));
             }
        

        【讨论】:

        • 为什么数据的价值总是[],请在发帖前说明你的答案!
        • 因为函数不会监听数据的任何变化。如果我们需要获取最新数据,请使用可以访问以前数据的更新程序功能。或者使用useEffect 监听数据变化,并在依赖数组中提供data。评论前阅读文档!
        • @adel data 不会有更新的值,除非你使用 useEffect,闭包是如何工作的,请刷新基础
        • @phantomCoder 大声笑我知道反应比你好,我只是要求他澄清答案以供其他人理解。因为问题是反应更新状态是异步的,为什么数据不会立即更新。
        • @adel 异步并不是数据不更新的原因。你所说的对setState 是正确的,但对useState 是不正确的。即使您等待 1 小时,data 仍将拥有初始数据。我们有更新函数和 useEffect 是有原因的。
        猜你喜欢
        • 2020-07-17
        • 1970-01-01
        • 1970-01-01
        • 2020-07-01
        • 2011-12-17
        • 1970-01-01
        • 2020-10-20
        • 2021-07-04
        • 1970-01-01
        相关资源
        最近更新 更多