reactjstypescriptwebsocketsignalr

Websocket data process with React


I am writing a real time application using React and websocket, there is a problem, I get the data from websocket, there is no problem here, but when it scrolled, I wrote the following code to get more code, it worked, but this time it renders the same data over and over again, even though there are 10 data in the db. What is the reason for this? ( [. ..prevPost,...prev] structure, I combine new data and old data in the string, if I remove it, the problem continues the same, if I remove it, I mean to give only the post variable, this time it does not add the old data and renders the page completely. I write my background using dotnet websocket signalr.

import React, { useEffect, useState, useRef } from "react";
import { PostLayout } from "../Components/PostLayout";
import { Post } from "../Components/Post";
import { Loading } from "../Components/Loading";
import { HubConnectionBuilder, HttpTransportType } from "@microsoft/signalr";

export const Home = () => {
  const [post, setPost] = useState([]);
  const page = useRef(0);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const connection = new HubConnectionBuilder()
      .withUrl("http://localhost:5226/posts", {
        transport: HttpTransportType.WebSockets,
      })
      .build();
    const loader = () => {
      connection.on("ReceivePosts", (post) => {
        setPost((prevPosts) => [...prevPosts, ...post]);
        setLoading(false);
      });

      connection.on("SendPost", (post) => {
        setPost((prev) => [...prev, ...post]);
        setLoading(false);
      });

      connection
        .start()
        .then(() => {
          connection.invoke("GetPosts", page.current, 5).then((res) => {
            console.log(res);
          });
        })
        .catch((err) => console.log("Error: ", err.toString()));
    };
    loader();
    const handleScroll = () => {
      if (window.innerHeight + window.scrollY >= document.body.offsetHeight && !loading) {
          page.current += 1;
          connection.invoke("GetPosts", page.current, 3)
              .then((res) => {
                  console.log(res);
                  setLoading(false);
              })
              .catch((err) => {
                  console.log("Error: ", err.toString());
                  setLoading(false);
              });
      }
    };
    window.addEventListener("scroll", handleScroll);
    return () => {
      window.removeEventListener("scroll", handleScroll);
    };
  }, [loading]);

  return (
    <>
      <div className={"grid columns-10 justify-center row-auto gap-8 top-5"}>
        <div className={"w-full "}>
          <PostLayout>
            <div className={"w-full flex flex-col gap-8 "}>
              {loading ? (
                <div className="relative top-32">
                  <Loading />
                </div>
              ) : (
                post.map((prop, index) => {
                  return (
                    <Post
                      key={index}
                      author={prop.author}
                      text={prop.content}
                      url={prop.url}
                      image={prop.image}
                    />
                  );
                })
              )}
            </div>
          </PostLayout>
        </div>
      </div>
    </>
  );
};

Solution

  • I am not familiar with the @microsoft/signalr library, but my guess is, scrolling causes an endless loop of invoking GetPosts and collecting the data via ReceivePosts and adding it to the state.

    To be precise, your handleScroll function calls connection.invoke("GetPosts", page.current, 3) and (I'd assume) your connection.on("ReceivePosts") listener will receive the same posts from the DB over an over again, adding them to the state.