【问题标题】:How to execute a sort after loading in data into an array in UseEffect - React Native如何在将数据加载到 UseEffect 中的数组后执行排序 - React Native
【发布时间】:2020-11-19 21:57:39
【问题描述】:

我正在尝试创建一个聊天应用程序,但出现了一个小问题。每当我从 firebase 加载消息时,它们都会以未排序的顺序出现在聊天应用程序中,因此我尝试按时间戳对消息进行排序,以便它们按顺序显示。如果我在 useEffect 的 onReceive 中移动 sort 和 setMessages,我可以做到这一点,但我觉得这将非常低效,因为它会为从 firebase 检索到的每条消息单独排序和设置消息。在所有消息都加载到数组中之后,我想在最后做这一切。

现在有了我的日志,我明白了:

[REDACTED TIME]  LOG      []
[REDACTED TIME]  LOG      pushing into loadedMessages
[REDACTED TIME]  LOG      pushing into loadedMessages

所以它首先打印(空)数组,然后加载消息。如何确保以正确的顺序完成此操作?

  useEffect(() => {
    // Gets User ID
    fetchUserId(getUserId());

    const messagesRef = firebase.database().ref(`${companySymbol}Messages`);
    messagesRef.off();

    messagesRef.off();
    const onReceive = async (data) => {
      const message = data.val();
      const iMessage = {
        _id: message._id,
        text: message.text,
        createdAt: new Date(message.createdAt),
        user: {
          _id: message.user._id,
          name: message.user.name,
        },
      };
      loadedMessages.push(iMessage);
      console.log('pushing into loadedMessages');
    };
    messagesRef.on('child_added', onReceive);

    loadedMessages.sort(
      (message1, message2) => message2.createdAt - message1.createdAt,
    );

    console.log(loadedMessages);

    return () => {
      console.log('useEffect Return:');
      messagesRef.off();
    };
  }, []);

【问题讨论】:

  • 你怎么知道所有的消息都收到了?是否有任何标志或参数表明已完成消息接收?比如消息的数量或任何事件。
  • @GaneshKarewad 我不确定。我认为 firebase 获取消息会自动停止,或者可能有一些 firebase 提供的指标,一旦完成这项工作,我就可以对数组进行排序。如果不是,那么在这里排序而不是在每次插入后排序更好的方法是什么?
  • 而不是使用事件 child_added,你应该使用 value,它会给你一个项目列表而不是每次一个值,你可以对所有值进行排序。
  • @GaneshKarewad 我需要它在添加消息后继续更新,尽管有点像实时聊天更新。 “价值”是否适用于该用例?

标签: javascript react-native firebase-realtime-database react-hooks use-effect


【解决方案1】:

我认为观点有点偏离。 这样做的正确方法是获取已排序的 firebase 数据。

Firebase 具有内置排序功能,尽管它确实有其局限性。

在我看来,您应该尝试以下方法:

const messagesRef = firebase.database().ref(`${companySymbol}Messages`);

messagesRef.orderByChild("createdAt").on("child_added", function(snapshot) {
  // the callback function once a new message has been created. 
  console.log(snapshot.val()); 
});

如果我可以再添加一件事,一旦您收到超过一千条左右的消息,从时间的尽头带出每条消息可能会有点麻烦,所以我建议限制它。例如,可以使用内置的限制函数limitToLast(1000) 来实现。

祝你好运!

【讨论】:

    【解决方案2】:

    嗯,数据库的名称是“实时数据库”。您正在使用“child_added”侦听器,每次将新对象添加到 Messages 集合时都会触发该侦听器。 onReceive 回调应该进行排序 - 否则消息的顺序将不正确。是的,这对于第一次加载来说效率很低,因为您的“child_added”很可能会为从集合返回的每个项目触发,并且您将重复排序。

    您可以探索的替代方法是拥有一个 .once 侦听器:https://firebase.google.com/docs/database/web/read-and-write#read_data_once 第一次在应用中填充数据时。这将返回您需要的所有数据。完成后,您可以创建“child_added”侦听器并仅侦听新对象。这种方式 onReceive 不应该在第一次调用时那么频繁,之后对每一个进入的新项目进行排序已经很有意义了。

    也看看排序:https://firebase.google.com/docs/database/web/lists-of-data#sorting_and_filtering_data

    您也许能够以正确的顺序返回消息。

    此外,如果您需要查询,请查看 firestore...

    【讨论】:

    • 谢谢,我会看看这个,看看它是否有效。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-21
    • 2021-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多