【问题标题】:Show the previous content for 5 seconds even if the state updates?即使状态更新,也显示之前的内容 5 秒?
【发布时间】:2021-08-14 22:17:06
【问题描述】:

我有一个使用 Django 后端的 React 应用程序,我使用 webSocket 与后端连接,当有一些变化时更新状态。但是变化非常迅速,所以只有最后的变化是可见的。我想在显示下一条消息之前显示上一条消息一段时间。这是我的代码

import React, { useEffect, useState, useRef } from "react";

const Text = () => {
  const [message, setMessage] = useState("");
  const webSocket = useRef(null);

  useEffect(() => {
    webSocket.current = new WebSocket("ws://localhost:8000/ws/some_url/");
    webSocket.current.onmessage = (res) => {
      const data = JSON.parse(res.data);
      setMessage(data.message);
    };
    return () => webSocket.current.close();
  }, []);

  return <p>{message}</p>;
};

export default Text;

所以消息应该在一定时间内可见(以秒为单位,例如 - 5 秒),然后应该显示下一条消息。知道如何做到这一点吗?

【问题讨论】:

  • 您希望减速使用去抖动、节流还是排队?
  • 哪个最简单
  • 它们在语义上是不同的,你应该考虑哪一个对你从 websocket 显示的数据最有意义。
  • 我是初学者,所以对这些术语不太了解,我正在寻找一个简单的解决方案

标签: javascript reactjs websocket react-hooks


【解决方案1】:
const Text = () => {
  const [messages, setMessages] = useState([]);
  const currentMessage = messages[0] || "";

  const [timer, setTimer] = useState(null);

  // webSocket ref missing? ;-)

  useEffect(() => {
    webSocket.current = new WebSocket("ws://localhost:8000/ws/some_url/");
    webSocket.current.onmessage = (res) => {
      const data = JSON.parse(res.data);
      setMessages((prevState) => [ ...prevState, data.message]);
    };
    return () => webSocket.current.close();
  }, []);

  // Remove the current message in 5 seconds.
  useEffect(() => {
    if (timer || !messages.length) return;

    setTimer(setTimeout(() => {
      setMessages((prevState) => prevState.slice(1));
      setTimer(null);
    }, 5000));
  }, [messages, timer]);

  return <p>{currentMessage}</p>;
};

【讨论】:

  • 哇,这么聪明的解决方案。这对我来说非常有效。我会把它标记为正确答案。
  • 这里要注意:如果消息的发送速度比您删除它们的速度快,则messages 数组的大小将会爆炸。如果您在有限的时间内进行调试,这可能没问题。否则,您还需要设置大小限制和丢弃消息的方式。
  • 不,情况并非如此,我对上面的代码有一些问题。如果我继续从后端接收消息,则 currentMessage 仅在我们停止接收消息时才会更改。我想在收到消息时更改 currentMessage。我们怎样才能做到这一点?
  • 啊,是的,很抱歉。我将编辑答案:只有在弹出消息时才应重置超时,而不是排队。
【解决方案2】:

您可以创建一个自定义挂钩来处理消息转换。在显示下一条消息之前将您希望等待的时间作为参数传递。您可以在代码的其他部分使用它:

使用Queu.js

const useQueu = time => {
  const [current, setCurrent] = useState(null); //--> current message
  const queu = useRef([]); //--> messages

  useEffect(() => {
    const timeout = setTimeout(() => {
      setCurrent(queu.current.shift());
    }, time);
    return () => clearTimeout(timeout);
  }, [current]);

  const add = obj => {
    if (!current) setCurrent(obj); //--> don't wait - render immediately
    else {
      queu.current.push(obj);
    }
  };
  return [current, add];
};

Text.js

const Text = () => {
  const [message, add] = useQue(5000);
  const webSocket = useRef(null);

  useEffect(() => {
    webSocket.current = new WebSocket("ws://localhost:8000/ws/some_url/");
    webSocket.current.onmessage = (res) => {
      const data = JSON.parse(res.data);
      add(data.message); //--> add new message
    };
    return () => webSocket.current.close();
  }, []);

  return <p>{message}</p>;
};

Working example

【讨论】:

    猜你喜欢
    • 2022-12-06
    • 2011-08-12
    • 2021-07-10
    • 1970-01-01
    • 1970-01-01
    • 2011-11-07
    • 1970-01-01
    • 2019-02-13
    • 2023-01-28
    相关资源
    最近更新 更多