简体   繁体   English

useState 没有正确更新数组

[英]useState not updating an array correctly

I'm using React with Firebase to fetch data from firestore and display it to the user.我正在使用 React 和 Firebase 从 firestore 获取数据并将其显示给用户。 Within a useEffect hook, I fetch the data and add it to an array of json objects.在 useEffect 挂钩中,我获取数据并将其添加到 json 个对象的数组中。 However, when adding a new element to the array, the previous one gets deleted.但是,当向数组添加新元素时,前一个元素将被删除。 Below will be relevant portions of code.下面将是代码的相关部分。

const [items, setItems] = useState([]);
const [isLoading, setLoading] = useState(true);
const { currentUser } = useAuth();

function addItemToList(i) {
  const updatedList = [
    ...items,
    {
      data: i.data(),
      ref: i.ref
    }
  ]

  return updatedList;
} 
useEffect(() => {
  firestore.collection('items').where('uid', '==', currentUser.uid).get().then((itemSnapshot) => {
    itemSnapshot.forEach((doc) => {
      setItems(addItemToList(doc));
    })
  })
  setLoading(false);
}, []);

I've also tried updating the items list within the useEffect hook, but it produces the same bug.我还尝试更新useEffect挂钩中的items列表,但它会产生相同的错误。

You need to add "addItemToList" to the dependencies of the useEffect hook.您需要将“addItemToList”添加到 useEffect 挂钩的依赖项中。

Because you haven't done this, the effect references an old version of that function which references an old version of the items array.因为您还没有这样做,所以效果引用了旧版本的 function,它引用了旧版本的 items 数组。

You just use itemSnapshot.map like this:您只需像这样使用itemSnapshot.map

firestore.collection('items').where('uid', '==', currentUser.uid).get().then((itemSnapshot) => {
    setItems(
      itemSnapshot.map((doc) => ({
        data: i.data(),
        ref: i.ref,
      })),
    );
  })

Let me take a moment to explain what is happening here.让我花点时间解释一下这里发生的事情。

Your have to think in your react component as a "Snapshot", where a snapshot is the result of a render.您必须将反应组件视为“快照”,其中快照是渲染的结果。 Each snapshot points to a state created by useState and only to that one.每个快照都指向由 useState 创建的 state,并且仅指向该快照。 What does this mean?这是什么意思?

The first time your component renders (first snapshot) the items variable returned by useState is pointing to an empty array and as long as that snapshot is alive it would be pointing to that array.组件第一次呈现(第一个快照)时,useState 返回的 items 变量指向一个空数组,只要该快照存在,它就会指向该数组。

So, lets take a look to the function called by useEffect那么,让我们看一下 useEffect 调用的 function

  firestore.collection('items').where('uid', '==', currentUser.uid).get().then((itemSnapshot) => {
    itemSnapshot.forEach((doc) => {
      setItems(addItemToList(doc));
    })
  })
  setLoading(false);

you are calling the set function for items once per elemtent in firebase query result and each call is seting a value that is the result of calling addItemToList您正在为 firebase 查询结果中的每个元素调用一次集合 function,并且每次调用都设置一个值,该值是调用 addItemToList 的结果

function addItemToList(i) {
  const updatedList = [
    ...items,
    {
      data: i.data(),
      ref: i.ref
    }
  ]

  return updatedList;
} 

the point here is that you are always destructuring...items which is always the items variable that the snapshot of the component is pointing to and it would not be updated until the component re rederds.这里的要点是你总是在解构...items,它总是组件快照指向的 items 变量,并且在组件重新更新之前不会更新。

So, basically you all aways doing updatedList = [...[], {... } ] becauses items has to wait to take update his value.所以,基本上你们都在做 updatedList = [...[], {... } ] 因为项目必须等待更新他的价值。

@Viet already responded with something good, which I think it's the best option @Viet 已经回复了一些好东西,我认为这是最好的选择

mapping the result of the query to an array and updating the array with the result of the map a parameter.将查询结果映射到数组,并使用 map 参数的结果更新数组。

useEffect(() => {
  firestore.collection('items').where('uid', '==', currentUser.uid).get().then((itemSnapshot) => {
    const result = [];
      itemSnapshot.forEach((doc) => {
        result.push({
          data: i.data(),
          ref: i.ref
        });
      })
    setItems(result);
  })
  setLoading(false);
}, []);

Instead of running it for each value maybe you should try to map it as a list and update the state once与其为每个值运行它,不如尝试将 map 作为列表并更新 state 一次

function addItemsToList(newItems) {
  const updatedList = [
    ...items,
    ...newItems
  ]

  return updatedList;
} 

useEffect(() => {
  firestore.collection('items').where('uid', '==', currentUser.uid).get().then((itemSnapshot) => {
    const docs = itemSnapshot.map((doc) => ({
       data: doc.data(),
       ref: doc.ref
    });
    setItems(addItemsToList(docs));
  })
  setLoading(false);
}, []);

You are using spread operator in a wrong way!您以错误的方式使用传播运算符! This way will not update the array.这种方式不会更新数组。

You can do that by using es6 spread to concat multiple arrays something like below:您可以通过使用es6 spread 连接多个 arrays 来做到这一点,如下所示:

const updatedList = [
    ...items,
    ...[{ data: i.data(), ref: i.ref }]
  ]

To know more: Using es6 spread to concat multiple arrays了解更多: 使用 es6 spread to concat multiple arrays

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 React & Firebase,useState 不更新,并传入空数组到文档中的数组 - React & Firebase, useState not updating, and passing in empty array, to array in document useState 没有立即更新 state - useState is not updating state immediately 从 Firestore 获取值时 useState 不更新 - useState not updating when getting values from Firestore 我如何让 usestate 在更新其值之前等待响应 - how do i make usestate wait for a response before updating its value 从 firestore 获取数据后正确更新 state - Updating the state correctly after fetch data from firestore forEach 循环返回值,但我的反应 useState 值只返回一个数组 obj - forEach loop returning the value but my react useState value only returning one array obj Azure.Messaging.ServiceBus QueueProperties 属性 DefaultMessageTimeToLive 未正确更新 - Azure.Messaging.ServiceBus QueueProperties property DefaultMessageTimeToLive not updating correctly 更新数组 Map 中的值 flutter Firebase - updating Map values in array flutter Firebase Swiftui 导航链接未正确更新 gridview 中每个用户的页面 - Swiftui Navigation link not updating correctly with each individual user's page in a gridview 使用 typescript map 数组类型更新 Firestore 文档 - Updating Firestore document with typescript map array type
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM