skip to Main Content

I have an array that contains other arrays:

export const ArtifactArray = [
  AccessoriesArtifacts,
  BodyArtifacts,
  CloakArtifacts,
  FeetArtifacts,
  HandsArtifacts,
  HeadArtifacts,
  LeftHandArtifacts,
  MainHandArtifacts,
  NeckArtifacts
]

Each of these arrays contain objects:

export const BodyArtifacts = [
  WonderArmor,
  BrimstoneBreastplate,
  PetrifiedWoodBreastplate,
  DragonScaleArmor,
  RibCage,
  GreatBasilistScales,
  TitansCuirass,
  CyclopsKingTunic,
];

Later on I’m iterating through the array and displaying all of these objects on the screen like this:

{ArtifactArray.map((array, index) => (
  <Fragment key={index}>
    {array.map((artifact, index) => (
      <ArtifactsBlock
        key={index}
        src={artifact.pic}
        name={artifact.name}
      />
    ))}
  </Fragment>
))}

Everything works as expected.

Then I’m trying to add a pagination to it, and that’s where the problem begins. I want to return only 20 objects per page (120 in total). But how do I do that if those arrays don’t have the same number of objects in each? If I use array.slice(0, 20), array.slice(20, 40), etc. by the end of some of those arrays it will return 11 or 9 instead. Of course I could get rid of those inner arrays and simply lump all objects into one array, but that’s clunky as hell. I’d like to keep it the way it is now.

2

Answers


  1. How about flattening your list?

    {ArtifactArray.flat().slice(i, i + pageLen).map(artifact, index) => (
      <ArtifactsBlock
        key={index}
        src={artifact.pic}
        name={artifact.name}
      />
    )}
    
    Login or Signup to reply.
  2. You can flatten the arrays of objects down to one array, and then use the length of that array plus a "limit" of the number of items to show to determine how you’re going to slice your data.

    Here’s a small working example which uses a small dataset (a total of eleven items). The data is flattened and passed into the component. There are two states: one for the page, and one for the limit. Note: here the limit is set to two items per page.

    When the component is rendered it calls both the getPages and getArtifacts functions. They build both a series of page buttons, and an array of artifacts using the information in the page and limit states.

    const { useState } = React;
    
    function Example({ artifacts }) {
    
      const [ page, setPage ] = useState(0);
      const [ limit, setLimit ] = useState(2);
    
      // Return a subset of data from the artifacts state based
      // on the page number, and the page limit
      function getArtifacts() {
        return artifacts
          .slice(page * limit, (page * limit) + limit)
          .map(artifact => {
            return (
              <Artifact
                key={artifact.id}
                data={artifact}
              />
            );
          });
      }
    
      // Update the page state
      function handlePage(e) {
        const { dataset: { page } } = e.target;
        setPage(+page);
      }
    
      // Create a series of pages based on the number of objects
      // in the artifacts state, and the page limit. Add an active prop
      // to indicate which page button should be highlighted
      function getPages() {
    
        const arr = [];
        const mod = artifacts.length / limit;
        const pages = mod % limit === 0 ? mod : Math.floor(mod) + 1;
    
        for (let p = 0; p < pages; p++) {
          arr.push((
            <Page
              key={p}
              number={p}
              active={p === page}
              handlePage={handlePage}
            />)
          );
        }
    
        return arr;
    
      }
    
      // Get the pages and the artifacts
      return (
        <main>
          <h2>Artifacts</h2>
          <section className="pages">
            {getPages()}
          </section>
          <section className="artifacts">
            {getArtifacts()}
          </section>
        </main>
      );
    
    }
    
    // Return an artifact name
    function Artifact({ data }) {
      return <section><h4>{data.name}</h4></section>;
    }
    
    // Return a page
    function Page({ number, active, handlePage }) {
      
      const cn = ['page', active && 'active'].join(' ');
      
      return (
        <button
          className={cn}
          data-page={number}
          type="button"
          onClick={handlePage}
        >{number + 1}
        </button>
      );
    
    }
    
    const bodyArtifacts=[{id:"ba1",name:"WonderArmor"},{id:"ba2",name:"BrimstoneBreastplate"},{id:"ba3",name:"PetrifiedWoodBreastplate"},{id:"ba4",name:"DragonScaleArmor"},{id:"ba5",name:"GreatBasilistScales"},{id:"ba6",name:"TitansCuirass"},{id:"ba7",name:"CyclopsKingTunic"}];
    const cloakArtifacts=[{id:"ca1",name:"RedCloak"},{id:"ca2",name:"BlueCloak"},{id:"ca3",name:"PinkCloak"},{id:"ca4",name:"GoldCloak"}];
    const artifacts=[bodyArtifacts,cloakArtifacts];
    
    const node = document.getElementById('root');
    const root = ReactDOM.createRoot(node);
    
    // Pass in the flattened data
    root.render(<Example artifacts={artifacts.flat()} />);
    .page { width: 30px; aspect-ratio: 1; border-radius: 5px;}
    .page:not(:last-child) { margin-right: 0.25rem; }
    .page:hover:not(.active) { background-color: #fffff0; cursor: pointer; }
    .active { background-color: lightgreen; }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.min.js"></script>
    <div id="root"></div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search