<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kevin</title>
    <description>The latest articles on DEV Community by Kevin (@romkev).</description>
    <link>https://dev.to/romkev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1427032%2Fb221523c-5fd9-4958-a711-5de5b9f16977.png</url>
      <title>DEV Community: Kevin</title>
      <link>https://dev.to/romkev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/romkev"/>
    <language>en</language>
    <item>
      <title>Infinite Scroll in Nextjs and typescript</title>
      <dc:creator>Kevin</dc:creator>
      <pubDate>Wed, 19 Jun 2024 23:14:39 +0000</pubDate>
      <link>https://dev.to/romkev/infinite-scroll-in-nextjs-and-typescript-5a6k</link>
      <guid>https://dev.to/romkev/infinite-scroll-in-nextjs-and-typescript-5a6k</guid>
      <description>&lt;p&gt;After a couple of days I finally was able to achieve an infinite scroll on my project. Here is yet another time saving snippet that you can use to achieve the same in a shorter time frame. As usual this is not a tutorial but a quick post to help a fellow developer save time on implementing an infinite scroll. You'll have to edit the code to fit the needs of your project.&lt;/p&gt;

&lt;p&gt;I am using nextUI for the frontend components.&lt;/p&gt;

&lt;p&gt;First we'll create a dummy user object&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface User {
  id: number;
  name: string;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I create a function to generate dummy data to populate the users array with user objects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const generateDummyData = (start: number, count: number): User[] =&amp;gt; {
  return Array.from({ length: count }, (_, i) =&amp;gt; ({
    id: start + i,
    name: `User ${start + i + 1}`,
  }));
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Time to implement a function called loadMoreUsers to fetch and append more user data as one scrolls down the page. I have simulated an api call time delay of 2 seconds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const loadMoreUsers = async () =&amp;gt; {
    if (loading || page &amp;gt;= 10) return;
    setLoading(true);
    await new Promise((resolve) =&amp;gt; setTimeout(resolve, 2000)); // Simulate 2-second delay
    const newUsers = generateDummyData(page * 10, 10);
    setUsers((prevUsers) =&amp;gt; [...prevUsers, ...newUsers]);
    setPage((prevPage) =&amp;gt; prevPage + 1);
    setLoading(false);
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next step is to use useEffect to load initial user data when the component mounts and to handle scrolling to load more users...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useEffect(() =&amp;gt; {
    if (!initialized.current) {
        initialized.current = true
        loadMoreUsers();
    }
  }, []);

  useEffect(() =&amp;gt; {
    const handleScroll = () =&amp;gt; {
        if (
            window.innerHeight +
              Math.max(
                window.pageYOffset,
                document.documentElement.scrollTop,
                document.body.scrollTop
              ) &amp;gt;
            document.documentElement.offsetHeight - 100
          ) {
            if (page &amp;lt; 10 &amp;amp;&amp;amp; page &amp;gt; 0) { 
                 loadMoreUsers();
              }
          } else {
            return;
          }

    };

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly we add an event listener for the scrollbar...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;window.addEventListener('scroll', handleScroll);
    return () =&amp;gt; window.removeEventListener('scroll', handleScroll);
  }, [page, loading]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Below is the full script...You can save it as a seperate file in the utils or components and simply import it to your project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Card, CardBody,Spinner,Button } from '@nextui-org/react';
import { useEffect, useState, useRef } from 'react';

interface User {
  id: number;
  name: string;
}

const generateDummyData = (start: number, count: number): User[] =&amp;gt; {
  return Array.from({ length: count }, (_, i) =&amp;gt; ({
    id: start + i,
    name: `User ${start + i + 1}`,
  }));
};

const UserListPage = () =&amp;gt; {
  const [users, setUsers] = useState&amp;lt;User[]&amp;gt;([]);
  const [loading, setLoading] = useState(false);
  const [page, setPage] = useState(0);

  const initialized = useRef(false)


  const loadMoreUsers = async () =&amp;gt; {
    if (loading || page &amp;gt;= 10) return;
    setLoading(true);
    await new Promise((resolve) =&amp;gt; setTimeout(resolve, 2000)); // Simulate 2-second delay
    const newUsers = generateDummyData(page * 10, 10);
    setUsers((prevUsers) =&amp;gt; [...prevUsers, ...newUsers]);
    setPage((prevPage) =&amp;gt; prevPage + 1);
    setLoading(false);
  };

  useEffect(() =&amp;gt; {
    if (!initialized.current) {
        initialized.current = true
        loadMoreUsers();
    }
  }, []);

  useEffect(() =&amp;gt; {
    const handleScroll = () =&amp;gt; {
        if (
            window.innerHeight +
              Math.max(
                window.pageYOffset,
                document.documentElement.scrollTop,
                document.body.scrollTop
              ) &amp;gt;
            document.documentElement.offsetHeight - 100
          ) {
            if (page &amp;lt; 10 &amp;amp;&amp;amp; page &amp;gt; 0) { 
                 loadMoreUsers();
              }
          } else {
            return;
          }

    };

    window.addEventListener('scroll', handleScroll);
    return () =&amp;gt; window.removeEventListener('scroll', handleScroll);
  }, [page, loading]);

  return (
    &amp;lt;div&amp;gt;
      {users.map((user) =&amp;gt; (
        &amp;lt;Card key={user.id}&amp;gt;
          &amp;lt;CardBody&amp;gt;
            &amp;lt;p&amp;gt;{user.name}&amp;lt;/p&amp;gt;
          &amp;lt;/CardBody&amp;gt;
        &amp;lt;/Card&amp;gt;
      ))}


        {loading ? (&amp;lt;Spinner /&amp;gt;) : (&amp;lt;Button onClick={loadMoreUsers}&amp;gt;Load more&amp;lt;/Button&amp;gt; )}
    &amp;lt;/div&amp;gt;
  );
};

export default UserListPage;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it folks....Now you can proceed to the other interesting parts of your project. Once I implement the api version I shall share as well&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>nestjs</category>
      <category>webdev</category>
      <category>fullstack</category>
    </item>
    <item>
      <title>Populating Select Input with data from an API using Nextjs and typescript</title>
      <dc:creator>Kevin</dc:creator>
      <pubDate>Tue, 04 Jun 2024 18:16:28 +0000</pubDate>
      <link>https://dev.to/romkev/populating-select-input-with-data-from-an-api-using-nextjs-and-typescript-4jcn</link>
      <guid>https://dev.to/romkev/populating-select-input-with-data-from-an-api-using-nextjs-and-typescript-4jcn</guid>
      <description>&lt;p&gt;After a series of nerve racking attempts and failures including combing through the entire internet I was finally able to achieve this feat. I shall share with you the function I currently use to populate select input using Nextjs from a Nest js api backend.&lt;/p&gt;

&lt;p&gt;Working with asynchronous functions can be a real paid and some of the errors I encountered while attempting this included&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Property 'data' does not exist on type 'Promise'&lt;/li&gt;
&lt;li&gt;Type {} is not assignable to type ReactNode&lt;/li&gt;
&lt;li&gt;And the biggest pain of them all....  “Invalid Hook Call” Error in React: Hooks Can Only Be Called Inside of a Function Component&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After literally taking days to achieve such a menial task I finally stumble upon a response on StackOverflow by Alarid (Shoutout to &lt;a href="https://stackoverflow.com/users/1379837/alarid"&gt;Alarid&lt;/a&gt;) that pointed me to the right direction.&lt;/p&gt;

&lt;p&gt;This is a front end implementation only and am using the following libaries&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nextjs&lt;/li&gt;
&lt;li&gt;Axios&lt;/li&gt;
&lt;li&gt;Nextui&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course this is just a "proof of concept" can can be edited to fit the libraries you are using on your nextjs project. For example you could be using the default 'fetch' method to pull data from an api endpoint or any other  third party library like swr or tanstack&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;To begin make sure the libraries are installed&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create file "apiSelect" in the filepath "@/app/lib/apiSelect.tsx"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use the code below and edit according to your need.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
import axios from "axios";
import { useState, useEffect } from "react";
import {Select, SelectItem} from "@nextui-org/react";

function apiSelect(url : string , lable: string, selected: string="") {
  const [options, setOptions] = useState&amp;lt;string[]&amp;gt;([]);

  useEffect(() =&amp;gt; {
    async function fetchData() {
      // Fetch data

      const { data } = await axios.get(url);
      const results: any[] = []
      // Store results in the results array
      data.forEach((value: any) =&amp;gt; {
        results.push({
          key: value.id,
          value: value.name,
        });
      });
      // Update the options state
      setOptions([
        ...results
      ])
    }

    // Trigger the fetch
    fetchData();
  }, []);



  return (

            &amp;lt;Select 
                label={lable}
                className="max-w-xs" 
            &amp;gt;
                {(options).map((option: any) =&amp;gt; (
                &amp;lt;SelectItem key={option.key}&amp;gt;
                    {option.value}
                &amp;lt;/SelectItem&amp;gt;
                ))}
            &amp;lt;/Select&amp;gt;
  );
}

export default apiSelect;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Incase you need to use authentication tokens you can include the token variable as an argument and implement using axios as shown below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import axios from "axios";
import { useState, useEffect } from "react";
import {Select, SelectItem} from "@nextui-org/react";

function apiSelect(url : string , token : string, lable: string, selected: string="") {
  const [options, setOptions] = useState&amp;lt;string[]&amp;gt;([]);

  useEffect(() =&amp;gt; {
    async function fetchData() {
      // Fetch data
      const config = {
        headers: { Authorization: `Bearer ${token}` }
     };
      const { data } = await axios.get(url, config);
      const results: any[] = []
      // Store results in the results array
      data.forEach((value: any) =&amp;gt; {
        results.push({
          key: value.id,
          value: value.name,
        });
      });
      // Update the options state
      setOptions([
        ...results
      ])
    }

    // Trigger the fetch
    fetchData();
  }, []);



  return (

            &amp;lt;Select 
                label={lable}
                className="max-w-xs" 
            &amp;gt;
                {(options).map((option: any) =&amp;gt; (
                &amp;lt;SelectItem key={option.key}&amp;gt;
                    {option.value}
                &amp;lt;/SelectItem&amp;gt;
                ))}
            &amp;lt;/Select&amp;gt;
  );


export default apiSelect;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Import the function to page.tsx file so that you can call the function.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;import apiSelect from "@/app/lib/apiSelect";&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Call the function&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You use the example below to call the function&lt;br&gt;
With Token&lt;br&gt;
 &lt;code&gt;{apiSelect(url, token, "Select a Role")}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Without token&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{apiSelect(url, "Select a Role")}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Hope this helps save you lots of hours trying to figure this out...&lt;/p&gt;

&lt;p&gt;Peace&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>nestjs</category>
      <category>node</category>
      <category>api</category>
    </item>
  </channel>
</rss>
