skip to Main Content
  const [currentIndexes, setCurrentIndexes] = useState([1,2,3,4]);
  let displayCreditorsData = currentIndexes.map((e) => allCreditorsData[e]);
  const totalCreditors = allCreditorsData.length;

  function nextCards() {
    let indexes=[];
    currentIndexes.map((position, index) => {
      if (position === allCreditorsData.length) {
        return indexes.push((position = 0));
      } else {
        return indexes.push(position + 1);
      }
    });
    setCurrentIndexes(indexes);
    displayCreditorsData = (indexes.map((e) => allCreditorsData[e]));
  }

  function prevCards() {
    let indexes = [];
    currentIndexes.map((position, index) => {
      if (position === 0) {
        return indexes.push((position = totalCreditors - 1));
      } else {
        return indexes.push(position - 1);
      }
    });
    setCurrentIndexes(indexes);
    displayCreditorsData = (indexes.map((e) => allCreditorsData[e]));  
  }

I have the above code which lets me render some data in cards. If I have 4 or more than 4 data, I dont have any issue. But when I have less than 4, I get the extra card which is just the template of the card design. I tried to limit currentIndexes state to [1], but that than only displays 1 card in the space which can accomodate 4 in total.

I checked other solutions but they were about just rendering the data in cards, and couldn’t address my problem properly. How do I solve this issue?

2

Answers


  1. Chosen as BEST ANSWER

    Defined states on top so that we can use each of them in any place we want without having to worry about getting not defined error

    const [loading, setLoading] = useState(false);
    const [allCreditorsData, setAllCreditorsData] = useState([]);
    const [currentIndexes, setCurrentIndexes] = useState([]);
            
    // have to define currentIndexes as array state or else we will run into 
    //.map is not function or sth kind of error
            
    useEffect(() => {
     const allCreditors = () => {
      fetchAllCreditors()
       ?.then((response) => {
        setAllCreditorsData(response?.data);
        setLoading(true);
                
        //setCurrentIndexes is initialized with response?.data?.length because
        //if we do it with allCreditors?.length, it doesnt catch as value,
        //probably the useState render kind of issue
                     
        setCurrentIndexes(
         Array.from(
          { length: Math.min(4, response?.data?.length) },
           (_, i) => i
           )
          );
         })
        .catch((error) => {
          console.log(error);
        });
       };
     allCreditors();
    }, []);
    

    and finally we get the chunks from the array we receive into displayCreditorsData, which is then used within return<></> as needed.

    let displayCreditorsData = currentIndexes.map((e) => allCreditorsData[e]);
    const totalCreditors = allCreditorsData.length;
    
    const nextCards = () => {}
    const prevCards = () => {}
    

    for nextCard and prevCard card function @Anshu solution is perfect.


  2. Issue

    When allCreditorsData array size is less than 4, else block of nextCards and prevCards leads to pushing unwanted index to indexes variable and further goes to dispalyCreditorsData.

    Solution

    Used two useEffect.

    First useEffect -> To fetch the data and to set the currentIndexes when YourComponent renders for the first time

    Second useEffect -> To set display data when any of the variables change from [allCreditorsData, currentIndexes]

    Added 1000ms delay to mimic asynchronous operation.

    import React, { useState, useEffect } from "react";
    
    const YourComponent = () => {
      const [allCreditorsData, setAllCreditorsData] = useState([]);
      const [displayCreditorsData, setDisplayCreditorsData] = useState([]);
      const [currentIndexes, setCurrentIndexes] = useState([]);
    
      useEffect(() => {
        const fetchData = async () => {
          setTimeout(() => {
            const hardcodedResponseData = [
              "Creditor 1",
              "Creditor 2",
              "Creditor 3",
            ];
            setAllCreditorsData(hardcodedResponseData);
            setCurrentIndexes(
              Array.from(
                { length: Math.min(4, hardcodedResponseData.length) },
                (_, i) => i
              )
            );
          }, 1000);
        };
    
        fetchData();
      }, []);
    
      useEffect(() => {
        if (allCreditorsData.length > 0) {
          setDisplayCreditorsData(
            currentIndexes.map((index) => allCreditorsData[index])
          );
        }
      }, [allCreditorsData, currentIndexes]);
    
      const nextCards = () => {
        const totalCreditors = allCreditorsData.length;
        setCurrentIndexes((prevIndexes) =>
          prevIndexes.map((index) => (index + 1) % totalCreditors)
        );
      };
    
      const prevCards = () => {
        const totalCreditors = allCreditorsData.length;
        setCurrentIndexes((prevIndexes) =>
          prevIndexes.map((index) => (index - 1 + totalCreditors) % totalCreditors)
        );
      };
    
      return (
        <div>
          {displayCreditorsData.map((creditor, index) => (
            <div key={index}>
              <p>{creditor}</p>
            </div>
          ))}
          {displayCreditorsData && displayCreditorsData.length > 0 && (
            <>
              {" "}
              <button onClick={prevCards}>Previous</button>
              <button onClick={nextCards}>Next</button>
            </>
          )}
        </div>
      );
    };
    
    export default YourComponent;
    
    

    Logic of event handler

    In nextCards function`(index + 1) % totalCreditors. It increments the index by 1 and then takes the modulo wrt totalCreditors. If the index reaches the end of the array, the modulo will return 0. Similarly, you can think for prevCards function

    If you wanna play around with code.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search