Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

make the live visitor counter change without refresh

My client want to make total visitor counter.

Is it possible to make the total visitor counter increase but when the user not refresh the page? so the users can see the total visitor increasing without refresh the page. What should i add to make it happen? Please kindly explain in detail because i am new to typescript.

here's my code

type visitortype={
  count: number;
}


const Footer = () => {
  const [visitor, setvisitor] = useState<visitortype>();

  useEffect(() => {
    fetch('https://count.cab/hit/ghG6Oirn0b')
    .then(response => response.json())
    .then(allvisitor=>  setvisitor(allvisitor))
    .catch(error => console.log(error));
  }, []);

 return (
    <GridItem
      w="100%"
      h={{ base: "80px", lg: "300px" }}
      colSpan={{ base: 8, lg: 4 }}
    >
      <VStack
        align={{ base: "center", lg: "stretch" }}
        marginTop={{ base: "0", lg: "60px" }}
        marginLeft={{ base: "0", lg: "50px" }}
      >
        <Box w={{ base: "100px", lg: "220px" }} paddingBottom={"10px"}>
          <Image src={imgLogoMd} alt="Logo" w="100%" />
          <HStack>
            <Text fontSize={{ base: "xs", lg: "md" }} textAlign={"justify"}>
              {visitor?.count} Visitor
            </Text>
          </HStack>
        </Box>
      </VStack>
    </GridItem>
  );

};
like image 554
Estherak23 Avatar asked Oct 27 '25 12:10

Estherak23


2 Answers

There are several strategies how you can get live or close to live counter:

  • Just poll your api every interval of your choice to get fresh stats. Super-simple to implement.
  • Long polling, probably 2nd-simple to implement but requires modifications on the backend
  • Use server side events
  • Use websockets via library, for example socket.io or sockjs

Only the first method not require any modifications on the backend, and most likely would be sufficient in your case. You just need to add a hook that will let you repeatedly poll an api: useInterval

Here is how it might look like


import {useEffect, useRef, useState} from 'react';

type CallbackType = (...args: any[]) => any;

// first you will need useInterval hook, you can implement it yourself or grab it from the lib. 
export function useInterval(callback: CallbackType, delay: number) { 
  const savedCallback = useRef<CallbackType | undefined>(); 
  useEffect(() => { 
    savedCallback.current = callback; 
  }, [callback]); 
  
  useEffect(() => { 
    function func() { 
      savedCallback.current?.(); 
    } 
    if (delay !== null) { 
      let id = setInterval(func, delay); 
      return () => clearInterval(id); 
    } 
  }, [delay]); 
}

// let's say we would like to get fresh stats every minute
const REFRESH_INTERVAL = 60 * 1000

const Footer = () => {
  const [visitor, setVisitor] = useState<visitortype>();

  useInterval(async () => {
    try {
      const response = await fetch('https://count.cab/hit/ghG6Oirn0b')
      const data = await response.json()
      setVisitor(data);
    } catch(error) {
      console.log(error);
    }
  }, REFRESH_INTERVAL);

 return (
    <GridItem
      w="100%"
      h={{ base: "80px", lg: "300px" }}
      colSpan={{ base: 8, lg: 4 }}
    >
      <VStack
        align={{ base: "center", lg: "stretch" }}
        marginTop={{ base: "0", lg: "60px" }}
        marginLeft={{ base: "0", lg: "50px" }}
      >
        <Box w={{ base: "100px", lg: "220px" }} paddingBottom={"10px"}>
          <Image src={imgLogoMd} alt="Logo" w="100%" />
          <HStack>
            <Text fontSize={{ base: "xs", lg: "md" }} textAlign={"justify"}>
              {visitor?.count} Visitor
            </Text>
          </HStack>
        </Box>
      </VStack>
    </GridItem>
  );

};

like image 96
Iaroslav Sobolev Avatar answered Oct 29 '25 03:10

Iaroslav Sobolev


The web client-server architecture is essentially based on the principle that only clients initiate requests.

Therefore the main solution to have a regular update without needing the visitor to manually take action every time, is to programmatically launch new requests at some pre-determined interval.

Here in React you can use e.g. useInterval hook from react-use:

import { useInterval } from 'react-use';

useInterval(
  () => {
    fetch('https://count.cab/hit/ghG6Oirn0b')
    .then(response => response.json())
    .then(allvisitor=>  setvisitor(allvisitor))
    .catch(error => console.log(error));
  },
  10_000 // Delay in milliseconds, e.g. here every 10 seconds
);

There are now more advanced ways to have a "live" connection between client and server that enable escaping from the original client-initiated request only scheme, like WebSockets (as mentionned in David's answer) and Server Events, but that would require to configure the server accordingly.

like image 27
ghybs Avatar answered Oct 29 '25 03:10

ghybs