Infinite Scroll Component not showing fetching items while using React Hooks

I’m doing an instant search functionality for food recipes and want to implement Infinite Scroll Component. What I want is to present a search bar as beginning, with no recipes show at all, then when user starts to type letter, it will fetch and show 8 items from data fetching from API, and when scroll down at bottom page it will continue fetch and show the next 8 items.

I’m following instruction from this link, but I encounter two issues:

  • If I set initial useState follow the instruction, it shows 8 empty placeholder (no data)

  • If I scroll down, it will fetch and show the next 8 empty placeholder with no data

If I set initial useState as empty array [], it works fine to fetch and show every placeholder with data in each, so what I understand about this maybe is the code Array.from(Array(8).keys(), n => n + 1) in useState and Array.from(Array(8).keys(), n => n + prevState.length + 1) in function fetchMoreListItems() are not relevant to my case.

My question is how to implement the right code so it can fetch the right data in number of object I want to, so it does with the scroll bar when I scroll down as well. Thank you Everyone!

Here’s my demo: gif

Here’s my code:

// Recipes.js

import React, { useState, useEffect } from "react"
import Axios from "axios"
import RecipeCard from "../components/RecipeCard"
import SearchBar from "../components/SearchBar"
import "../style/Recipes.css"

export default function Recipes() {
  
  const [isLoading, setIsLoading] = useState(false)
  const [query, setQuery] = useState("")
  const [recipes, setRecipes] = useState(Array.from(Array(8).keys(), n => n + 1))
  const [isFetching, setIsFetching] = useState(false)

  const url = `https://www.themealdb.com/api/json/v1/1/search.php?s=${query}`
    
    // function to search for the recipes when enter `search button`
    const searchRecipes = async () => {
      if (query !== "") {
        setIsLoading(true)
        const result = await Axios.get(url)
        console.log(result)
        setRecipes(result.data.meals)
        setQuery("")
        setIsLoading(false)
      } 
    }

    // do instant search when start typing any of letters
    useEffect(async () => {
      if (query !== "") {
        const result = await Axios.get(url)
        console.log(result);
        setRecipes(result.data.meals)
      }
    }, [query])

    // handle handleScroll
    useEffect(() => {
      window.addEventListener('scroll', handleScroll);
      return () => window.removeEventListener('scroll', handleScroll);
    }, [])

    function handleScroll() {
      if (window.innerHeight + document.documentElement.scrollTop + 1 >= document.documentElement.offsetHeight) return
      setIsFetching(true)
    }

    useEffect(() => {
      if (!isFetching) return
      fetchMoreListItems()
    }, [isFetching])

    function fetchMoreListItems() {
      setTimeout(() => {
        setRecipes(prevState => ([...prevState, ...Array.from(Array(8).keys(), n => n + prevState.length + 1)]))
        setIsFetching(false)
      }, 2000);
    }

    const onChange = async e => {
      setQuery(e.target.value)
    }

    const handleSubmit = e => {
        e.preventDefault()
        searchRecipes()
    }

    const clearInput = () => {
      setRecipes([])
      setQuery("")
    }

    return (
        <div className="recipes">
            <div className="search-box">
              <h1>Recipe App</h1>
              <SearchBar
                  handleSubmit={handleSubmit}
                  value={query}
                  name="name"
                  onChange={onChange}
                  isLoading={isLoading}
              />
              {
                query.length !== 0 && 
                  <div className="close-icon" onClick={clearInput}>
                    <svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 1024 1024" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 0 0 203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"></path></svg>
                  </div>
              }
              <div className="search-result">
                {
                  recipes && query !== "" &&
                    recipes.slice(0, 5).map((val) => {
                      return (
                        <a className="search-item" href={val.strSource} target="_blank" rel="noopener noreferrer">
                          <p>{val.strMeal}</p>
                        </a>
                      )
                    })
                }
              </div>
            </div>
            <div className="recipes-container">
              {
                recipes && query !== null ?
                  recipes.map((recipe) => (
                      <RecipeCard 
                          key={recipe.idMeal}
                          recipe={recipe}
                      />
                  ))
                  : "We're sorry! No recipe found."
              }
            </div>
            {isFetching && 'Fetching more recipes...'}
        </div>
    )
}

TypeError: sentimentCurrent.map is not a function?

Trying to write a unit test for the below function.

I’m getting an error of

TypeError: sentimentCurrent.map is not a function

      65 |     console.log("sentimentData:",sentimentCurrent,typeof sentimentCurrent);
      66 | 
    > 67 |     sentimentCurrent.map(function (k, num) {
         |                      ^
      68 |       let dateCreated = new Date(k.created * 1000);
      69 | 
      70 |       DataInput.push({

The actual function is below, it takes in raw data and then prepares it to be used in a linegraph essentially.

export default function generateLineGraphPointsSentiment(
  sentimentData
) {
  console.log("sentimentData:",sentimentData,typeof sentimentData);
  if (sentimentData !=null) {
  const DataInput = [];

  Object.keys(sentimentData).map(function (key, item) {
    var sentimentCurrent = sentimentData[key];
    console.log("sentimentData:",sentimentCurrent,typeof sentimentCurrent);

    sentimentCurrent.map(function (k, num) {
      let dateCreated = new Date(k.created * 1000);

      DataInput.push({
        created: dateCreated,
        sentiment: k.sentiment,
        magnitude: k.magnitude,
        date: k.createdDay,
      });
    });

    // {created: 1601820360, sentiment: -0.1, magnitude: 0.1, createdDay: "2020-10-05"}
  });

The test case is as follows,

import '@testing-library/jest-dom';
import { render, screen } from '@testing-library/react';
import generateLineGraphPointsSentiment from './generateGraphPointsAnalysis';

const SentimentData = [
  {
    id: 96452,
    user_id: 'asdasd',
    sentiment: -0.1,
    magnitude: 1,
    created: 1629535060,
    createdDay: '2021-08-21',
  },
  {
    id: 96453,
    user_id: 'asdasd',
    sentiment: 1,
    magnitude: 1,
    created: 1629535063,
    createdDay: '2021-08-21',
  },
];

// const setSelectedDate = jest.fn();

describe('Generates Graph Points Sentiment', () => {
  it('should show loader for the LineGraphs graph if no data is present', () => {
    generateSentimentLineGraph = generateLineGraphPointsSentiment(SentimentData);
    console.log(generateSentimentLineGraph,SentimentData,typeof SentimentData);

    expect(generateSentimentLineGraph).toHaveReturned();
  });
});

Any ideas on what is wrong with my code? It works in dev currently, not sure why it’s failing this test now? I think it has something to do with either the type of data being processed, or how I’m using the map functions. Perhaps I can simplify the first map function?

Why is this user id not coming out of req.user;

This is my code for getting user info

router.post("/getuser", fetchuser, async (req, res) => {
  try {
    userId = req.user.id;
    const user = await User.findById(userId).select("-password");
    res.send(user);
  } catch (error) {
    console.error(error.message);
    res.status(500).send("Internal Server Error");
  }
});

and this is the code for middleware fetchuser

const fetchuser = async (req, res, next) => {
const token = req.header('auth-token');
if (!token) {
    res.status(401).send({ error: "Please authenticate using a valid token" })
}
try {
    const data = jwt.verify(token, process.env.SECRET);
    console.log(data);
    req.user = data.user;
    next();
} catch (error) {
    res.status(401).send({ error: "Please authenticate using a valid token" })
}
};

I am getting the user id in console.log but when I try to get the user id in the router.post then I am not able to get the user Info.
Here is the result I am getting.

Server is running on port 5000
Connected to database
{ id: '61e98c45a9d8818292b38505', iat: 1642743501 }
Cannot read properties of undefined (reading 'id')

Please can anyone tell me what is wrong with this?

Displaying shuffles answers in an array in their tags

const myQuestions = [
    {
        question: "What's 2+2?",
        answers: [
            { text: "4", correct: true }[0],
            { text: "2", correct: false }[1],
            { text: "10", correct: false }[2],
            { text: "1", correct: false }[3],
        ],
    },
];
function startQuiz() {
    container.style.visibility = "visible";
    btn_start.style.visibility = "hidden";
    showQuestion(myQuestions[0]);
}
function showQuestion(questionAndAnswers) {
    const shuffledAnswers = _.shuffle(questionAndAnswers.answers);
    questionTag.innerText = questionAndAnswers.question;
    shuffledAnswers.forEach((answer, idx) => {
        answerTag[0] = answer.text;
    });
}
        <h3 id="question"></h3>
        <div class="answers">
            <button id="answer1" class="answer"></button>
            <button id="answer2" class="answer"></button>
            <button id="answer3" class="answer"></button>
            <button id="answer4" class="answer"></button>
        </div>

After putting my answers and question in an array object, I shuffled them with lodash and was able to display the question in its right tag, how do I display the Shuffled answers in the answerTag. I keep getting errors of trouble reading text in my .foreach function.

Setting the TTL (expire) using new Redis-OM & Node Object Mapping

I came across the new Redis-OM Node Object Mapping functionality, I’ve not really experimented with Redis before but I thought now might be the time to give it a go.

Right now I have a basic function set up for creating a room but I would like the room to expire after say 24 hours (86400 seconds iirc).

export async function createRoom(data) {
    await connect();

    const repository = new Repository(schema, client);

    const room = repository.createEntity(data);

    const id = await repository.save(room);

    return id;
}

How do I set the TTL or expire time for an object using the Object Mapping approach… see my schema below.

class Room extends Entity {}
let schema = new Schema(
    Room,
    {
        code: { type: 'string' },
        playlist: { type: 'array', videos: { type: 'string' } },
    },
    {
        dataStructure: 'JSON',
    }
);

How to arrange an array with objects based on another array?

I have this unsorted array (containing objects)

   toSortArray = [{taskID: 1, "title": "something1", subtasks: {}},
                  {taskID: 5, "title": "something5", subtasks: {}},
                  {taskID: 8, "title": "something8", subtasks: {}}];

and I have this array that is dynamically populated based on the correct positioning of the taskIDs

sortingArray = [8, 1, 5];

What I am trying to do is to sort ‘toSortArray’ with the exact same order as stated in ‘sortingArray’.

I have found a somewhat called solution here stating this:

var arr = ['one','four','two'];
var test = [{
    key: 'one'
},{
  key: 'two'
},{
  key: 'four'
}];

function sortFunction(a,b){
    var indexA = arr.indexOf(a['key']);
    var indexB = arr.indexOf(b['key']);
    if(indexA < indexB) {
        return -1;
    }else if(indexA > indexB) {
        return 1;
    }else{
        return 0;        
    }
}

However, it doesn’t work for me. I replaced the placeholders for:

function sortFunction (a,b) {
        var indexA = sortingArray.indexOf(a["taskID"]);
        console.log(indexA);
        var indexB = sortingArray.indexOf(b["taskID"]);
        console.log(indexB);
        if (indexA < indexB) {
            return -1;
        } else if (indexA > indexB) {
            return 1;
        } else {
            return 0;
        }
    }

When I debugged (as you can see I am console logging the indexA and indexB). They always return -1, which means no such index is found.

My question is how to get to compare “taskID” value and the sortingArray elements.

Thank you 🙂

Most common javascript functions/methods for leetcode or coding in general

As I started my journey to learning how to code(like three weeks ago), I’ve been grinding on codewars while on udemy learning the basics of js, hmtl, and css. My question is this: to the experienced javascript engineers, what were/are the most common functions/methods you use when you write code or want to solve a leetcode problem that you have noticed? For the most part, I’ve been using .map,.filter,.reduce,.find,.join, and .split. Is there any other ones that you would recommend to study and have the ins and outs memorized?

How to use getJSON() method and make to visible in pug/html

I’ve made a comment page using nodejs and mongoDB. I’ve got it to the step where i get the data in the form of a JSON format. Now i want to convert it to a simple readable form in the pug/html page…

Here is the image of the data I’ve received from the database.
enter image description here

This is just a single line list element… i would also want to make a box and the data in a specific format like…

<div id="display>

 <THE USERNAME HERE>

 <THE TOPIC HERE>
 
 <THE COMMENT HERE...>

</div>

And here is the image of the way im using getJSON() method.
enter image description here

I need the data under the display div in the pug/html file.

Thank you.

Webpack Module Federation handling when the remote app is down/unavailable

I am currently exploring about micro frontend with Module Federation. I just forked a sandbox, tried it with success when the both modules available. It has 2 modules, app1 as the host, and app2 as the remote component. But as I think that each modules in module federation should be independent, I tried to make the app2 unavailable as I didn’t start it. Therefore I got error when I run the app1, it finished loading with displaying the fallback of the React’s Suspense, but milliseconds later, it becomes blank as there’s error I can’t retrieve thus I don’t really know.

After that, I tried Webpack’s Promise Based Dynamic Remotes, then my webpack-config.js becomes like this:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const { ModuleFederationPlugin } = require('webpack').container;
const ExternalTemplateRemotesPlugin = require('external-remotes-plugin');
const path = require('path');

module.exports = {
  entry: './src/index',
  mode: 'development',
  devServer: {
    static: path.join(__dirname, 'dist'),
    port: 3001,
  },
  output: {
    publicPath: 'auto',
  },
  module: {
    rules: [
      {
        test: /.jsx?$/,
        loader: 'babel-loader',
        exclude: /node_modules/,
        options: {
          presets: ['@babel/preset-react'],
        },
      },
    ],
  },
  plugins: [
    new ModuleFederationPlugin({
      name: 'app1',
      remotes: {
        app2: Promise((resolve) => {
          const urlParams = new URLSearchParams(window.location.search);
          const version = urlParams.get('app1VersionParam');
          // This part depends on how you plan on hosting and versioning your federated modules
          const remoteUrlWithVersion = '[app2Url]' + '/remoteEntry.js';
          const script = document.createElement('script');
          script.src = remoteUrlWithVersion;
          script.onload = () => {
            // the injected script has loaded and is available on window
            // we can now resolve this Promise
            const proxy = {
              get: (request) => window.app1.get(request),
              init: (arg) => {
                try {
                  return window.app1.init(arg);
                } catch (e) {
                  console.log('remote container already initialized');
                }
              },
            };
            resolve(proxy);
          };
          // inject this script with the src set to the versioned remoteEntry.js
          document.head.appendChild(script);
        }),
        // "app2@[app2Url]/remoteEntry.js",
      },
      shared: { react: { singleton: true }, 'react-dom': { singleton: true } },
    }),
    new ExternalTemplateRemotesPlugin(),
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),
  ],
};

I tried start the app1 again, then this error comes:

$ webpack serve
[webpack-cli] Failed to load '/home/projects/github-rl5uyr/app1/webpack.config.js' config
[webpack-cli] TypeError: undefined is not a promise
    at Promise (<anonymous>)
    at Object.eval (/home/projects/github-rl5uyr/app1/webpack.config.js:32:15)
    at Object.function (https://github-rl5uyr.w.staticblitz.com/blitz.01faa899fac41642342f4b7113feacabea334fa1.js:11:114831)
    at Module._compile (https://github-rl5uyr.w.staticblitz.com/blitz.01faa899fac41642342f4b7113feacabea334fa1.js:6:167880)
    at Object.Module._extensions..js (https://github-rl5uyr.w.staticblitz.com/blitz.01faa899fac41642342f4b7113feacabea334fa1.js:6:168239)
    at Module.load (https://github-rl5uyr.w.staticblitz.com/blitz.01faa899fac41642342f4b7113feacabea334fa1.js:6:166317)
    at Function.Module._load (https://github-rl5uyr.w.staticblitz.com/blitz.01faa899fac41642342f4b7113feacabea334fa1.js:6:163857)
    at Module.require (https://github-rl5uyr.w.staticblitz.com/blitz.01faa899fac41642342f4b7113feacabea334fa1.js:6:166635)
    at i (https://github-rl5uyr.w.staticblitz.com/blitz.01faa899fac41642342f4b7113feacabea334fa1.js:6:427483)
    at _0x5301a6 (https://github-rl5uyr.w.staticblitz.com/blitz.01faa899fac41642342f4b7113feacabea334fa1.js:11:114450)

So, can the module federations run independently each other? If not, what’s the real difference as normal library dependencies of monolith front end instead of this sophisticated micro frontend, that I assumed it should be able to work independently like microservices?

PDF.js reorder pages

I am using PDF.js read the content in page with help of regex. Now I want to reorganize pdf by changing order of pages. Such as move page 15 to 1, move page 7 to 2 etc…

I didn’t find such a functionality in PDF.js, is this possible to do?

How to import lodash library in js file

import { shuffle } from 'lodash';
    <script type="module" src="./script.js" defer></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.js" ></script>

How to solve this issue? the library is not loading and getting multiple errors such as
Uncaught TypeError: Failed to resolve module specifier “lodash”. Relative references must start with either “/”, “./”, or “../”.
or can’t import outside the module. How to fix it? My HTML head is above, I got the CDN from their website and I only need to import shuffle.

Razor pay give payment amount as one rupee incorrectly

I am trying to add razorpay payment gateway to my website. I use this method. I used code like below,

 

document.querySelector('.razor').setAttribute('data-amount', 4200)
    <form action="https://www.example.com/payment/success/" method="POST">
<script class="razor"
    src="https://checkout.razorpay.com/v1/checkout.js"
    data-key="rzp_live_1vs8SzfbPyOPH1" 
    data-currency="INR"
    data-buttontext="Pay with Razorpay"
    data-name="Acme Corp"
    data-image="https://i.imgur.com/sscxwyv.png"
    data-prefill.name=""
    data-prefill.email=""
    data-theme.color="#F37254"
></script>
<input type="hidden" custom="Hidden Element" name="hidden">
</form>

This code give payment amount as one rupee instead of 42 rupees. Where is the error happened? Code pen link here

Returning value from an mutliple async array in javascript

I feel that this problem has been asked before maybe I have a unique scenario I haven’t seen on github before, but I am fetching data from multiple sources at the same time which is create multiple arrays I need to loop through to grab the data needed. I am looking to
return the value of a simple array of twitch channels and have the value only logged once. Instead my logs are looping over empty arrays which is definitely unnecessary.


client.on("ready", async () => {
  const endeavorsServer = client.guilds.cache.get(process.env.DISCORD_GUILD_TOKEN)
  const connectedChannels = []
  let value
  let grabMembers = []

  // Fetch and get the list named 'members'
  await endeavorsServer.members.fetch().then((members) => {
    grabMembers = members
  })

  // Loop through every members
  grabMembers.forEach(async (member) => {
    value = await newMembers(member)
  })

  console.log(value)
  if (value && value.length) {
    console.log('val', value)
  }
})

async function newMembers(member) {
  const liveRoleId = process.env.DISCORD_LIVE_ROLE_ID
  const isBot = member.user.bot
  const liveRole = member.roles.cache.has(liveRoleId)
  let array = []
  let value = null
  if (!isBot && /* liveRole */ (member.user.username === 'member_id')) {
    value = await getDiscordUser(member.user)
  }

  if (value && value.twitch_channel) {
    array.push(value.twitch_channel)
  }
  return array
}

Why is this function still running on desktop?

I have this accordion in my footer that should only run on mobile.
When I have it run on desktop initially the function doesn’t run, which is what I want. But if I switch to mobile view and then back to desktop, the function is still working… I’m still able to click the h5 and show/hide the text below… this shouldn’t be happening on desktop though, I don’t understand the issue..

Codepen so you can see the resize issue.

// On resize run the check screen size function
$(window).on("resize", function (e) {
    checkScreenSize();
});
// Run the check screen size function on load
checkScreenSize();

// check screen size function
function checkScreenSize(){
    var newWindowWidth = $(window).width();

    // Run the accordion function on screens less than 1024
    if (newWindowWidth < 1024) {
        footerAccordion();
    } 
}

// Accordion function
function footerAccordion() {
    $('.footer__locations p').hide();
    $(".footer__locations").find("h5").click(function() {
        $(".footer__locations").find("h5").removeClass('active');
        $('.footer__locations p').slideUp();
        var selected = $(this).next('.footer__locations p');
        if (selected.is(":hidden")) {
        $(this).next('.footer__locations p').slideDown();
        $(this).toggleClass('active');
        }
    });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">

<footer class="footer">
    <div class="container-fluid">
        <div class="row">
            <div class="col-lg-6">
                <div class="row footer__locations-row">
                    <div class="col-lg-6 footer__locations">
                        <h5>TITLE TWO</h5>
                        <p>THIS IS SOME TEXT TWO</p>
                    </div>
                    <div class="col-lg-6 footer__locations">
                        <h5>TITLE TWO</h5>
                        <p>THIS IS SOME TEXT TWO</p>
                    </div>
                </div>
            </div>
        </div>
    </div>
</footer>

Android React Native WebView loading Recaptcha via script tab doesn’t doesn’t work

We have the following code being loaded into a WebView in React Native:

<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      display: flex;
      justify-content: left;
      align-items: top;
    }
  </style>
</head>
<body>
  <div id="inline-badge"></div>
  <script src="https://www.google.com/recaptcha/api.js?render=explicit&onload=onRecaptchaLoadCallback"></script>
  <script>
    alert('js is running');
    function onRecaptchaLoadCallback() {
      alert('onRecaptchaLoadCallback loaded');
    }
  </script>
</body>
</html>`

What is expected to happen is the code is loaded for Recaptcha from https://www.google.com. Once loaded the onload=onRecaptchaLoadCallback will call the onRecaptchaLoadCallback function.

This works on iOS. The alert for js is working is show, the after the script is loaded, the onRecaptchaLoadCallback function is called (and shows the alert contents)

On Android, we only get the first alert, but the onRecaptchaLoadCallback is never called.

Here is the WebView component code for reference:

<WebView
  nativeID={id}
  style={{ width: 0, height: 0 }}
  originWhitelist={['*']}
  startInLoadingState={true}
  javaScriptEnabledAndroid={true}
  javaScriptEnabled={true}
  domStorageEnabled={true}
  mixedContentMode="always"
  allowUniversalAccessFromFileURLs={true}
  source={{ html: recaptchaHtmlWithKey, baseUrl: 'https://www.our-site-url.com' }}
  onMessage={(event) => {
    onCheck(event.nativeEvent.data)
  }}
/>

Also to note, we do have the INTERNET permission set in the android gradle file.