Anni
Anni

Reputation: 177

Not able to access react State inside a function

I am new to javascript and react. I am trying to figure out why blockHeight state variable is not accessible inside the loadNewBlocks function which triggers when the user scrolls.

Current value of blockHeight is 0 but I am expecting this value which is set in setBlockHeight(data[data.length - 1].Height); in side useEffect. For e.g. value set inside the setBlockHeight is 14789 so I am expecting 14789 inside loadNewBlocks function. enter image description here

import { useState, useEffect } from "react";
import connect from "../../Backend/database/dbtest";
export default function test({ data }) {
  const [blocks, setBlocks] = useState([]);
  const [blockHeight, setBlockHeight] = useState(0);
  console.log("top block height: ", blockHeight);

  const loadNewBlocks = async () => {
    console.log(
      `Value in loadNewBlocks http://localhost:3000/api/fetchBlocks?blockHeight=${blockHeight}`
    );
    const res = await fetch(
      `http://localhost:3000/api/fetchBlocks?blockHeight=${blockHeight}`
    );

    if (!res.ok) {
      console.log("Error in fetching blocks");
      return;
    }
    const newBlocks = await res.json();
    setBlockHeight(newBlocks[newBlocks.length - 1].Height);
    setBlocks((prevBlocks) => [...prevBlocks, ...newBlocks]);
  };

  // Load Data on Scroll
  const handleScroll = async (e) => {
    if (
      e.target.documentElement.scrollTop + window.innerHeight >=
      e.target.documentElement.scrollHeight
    ) {
      loadNewBlocks();
    }
  };
  useEffect(() => {
    setBlocks(data);
    setBlockHeight(data[data.length - 1].Height);
    console.log("useEffect blockHeight", blockHeight);
  }, [data]);

  useEffect(() => {
    window.addEventListener("scroll", handleScroll);
  }, []);

  return (
    <div>
      <button className="border-2 bg-red-400"> Submit </button>
      {blocks.map((block) => (
        <div key={block.blockHeader.blockhash}>
          {block.blockHeader.blockhash}
        </div>
      ))}
    </div>
  );
}

export async function getServerSideProps() {
  const connection = await connect();
  const res = await fetch("http://localhost:3000/api/fetchBlocks");
  const data = await res.json();

  return {
    props: { data },
  };
}

Here is the updated solution. Used useRef to maintain the value.

import Link from "next/link";
import connect from "../../Backend/database/dbtest";
import { useEffect, useState, useRef, useCallback } from "react";
// import read from "../../Backend/database/read";
export default function Blocks({ data }) {
  const [blocks, setBlocks] = useState([]);

  const HeightRef = useRef();
  const isLoading = useRef(false);

  const MINUTE_MS = 500000;

  const loadNewBlocks = async () => {
    if (!isLoading.current) {
      isLoading.current = true;
      console.log(
        `http://localhost:3000/api/fetchBlocks?blockHeight=${HeightRef.current}`
      );

      const res = await fetch(
        `http://localhost:3000/api/fetchBlocks?blockHeight=${HeightRef.current}`
      );
      const newBlocks = await res.json();
      console.log("New Blocks: ", newBlocks);

      HeightRef.current = newBlocks[newBlocks.length - 1].Height;
      console.log("New Height: ", HeightRef.current);

      setBlocks((prevBlocks) => [...new Set([...prevBlocks, ...newBlocks])]);
      isLoading.current = false;
    }
  };

  const handleScroll = async (e) => {
    if (
      e.target.documentElement.scrollTop + window.innerHeight >=
      e.target.documentElement.scrollHeight
    ) {
      await loadNewBlocks();
    }
  };

  useEffect(() => {
    setBlocks(data);
    HeightRef.current = data[data.length - 1].Height;
    window.addEventListener("scroll", handleScroll);
  }, []);



  return (
    <div className="bg-black flex justify-center pt-[2em]">
      <div className="w-full h-full bg-gradient-to-r from-indigo-700 to-sky-600 rounded-2xl  text-white grid grid-rows-[4em_1fr] mx-[6em]">
        <div className=" text-4xl font-bold pl-[1em] pt-[1em]">
          Latest Blocks
        </div>
        <div className="pt-[2em]">
          <div className="grid grid-cols-[1fr_3fr_1fr_1fr] font-bold h-[3em] text-xl border-b-2">
            <div className="flex justify-center"> Block Height </div>
            <div className="flex justify-center">Block Header</div>
            <div className="flex justify-center"> Transactions </div>
            <div className="flex justify-center"> Block Size </div>
          </div>
          {blocks.map((block) => (
            <div
              key={block.blockHeader.blockhash}
              className="cursor-pointer grid grid-cols-[1fr_3fr_1fr_1fr] border-b-[1px] h-[4em] pt-[1em] hover:bg-gradient-to-r  from-purple-600 to-blue-400 rounded-2xl"
            >
              <div className="flex justify-center"> {block.Height} </div>
              <div className=" ">
                <Link href={`/block?blockhash=` + block.blockHeader.blockhash}>
                  <div className="flex justify-start px-[2em]">
                    {block.blockHeader.blockhash}
                  </div>
                </Link>
              </div>
              <div className="flex justify-center"> {block.TxCount} </div>
              <div className="flex justify-center"> {block.BlockSize} </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

export async function getServerSideProps() {
  const connection = await connect();
  // const blocks = JSON.parse(JSON.stringify(await read.main(false, false, 20)));
  const res = await fetch("http://localhost:3000/api/fetchBlocks");
  const data = await res.json();

  return {
    props: { data },
  };
}

Upvotes: 0

Views: 61

Answers (1)

Tomoe
Tomoe

Reputation: 416

To try to bring

useEffect(() => {
    window.addEventListener("scroll", handleScroll);
    - setBlocks(data);
    - setBlockHeight(data[data.length - 1].Height);
}, []);

change to

useEffect(() => {
    setBlocks(data);
    setBlockHeight(data[data.length - 1].Height);
}, [data]);

useEffect(() => {
    window.addEventListener("scroll", handleScroll);
}, []);

Make sure that only one thing is doing

By the way, a better approach would be to throttle your scrolling function you can use the lodash throttle method

So, I expect you to do this to maintain application optimization

const MAX_TIMES = 300

const handleScroll = () => {}

useEffect(() => {
   const throttleScroll = throttle(handleScroll, MAX_TIMES);

   window.addEventListener('scroll', throttleScroll);

   return () => {
      window.removeEventListener('scroll', throttleScroll)
   }
}, [])

Good Luck :)

Upvotes: 1

Related Questions