Display information in a paginated format using components

As a newcomer to React, I may use the wrong terms so please bear with me.

I am attempting to implement pagination for an array of components. To achieve this, I have divided the array into pages based on the desired number of items per page and stored each page in a new array like so:

const limit = 4
const numPages = 20
let pagewrapper = []

for (let i = 0; i < numPages; i++) {

  let start = i * limit
  let end = start + limit

  let pageItems = children.slice(start, end)

  // Skip first array push as 'page 1' is already showing.
  if (end != limit) {
    pagewrapper.push(<Grid gridContainerStyles={'grid-page__' + i} items={pageItems} />)
  }
}

Furthermore, I've added a basic button to display one page at a time.

    <Button
      onClick={this.pagerHandleClick}
    >
      {'Show more'}
    </Button>

The corresponding handler is:

  pagerHandleClick() {
    this.setState(state => ({
      page: state.page + 1,
    }))
  }

However, I'm now facing uncertainty on how to instruct each <Grid /> component to reveal itself. The solutions suggested online involve wrapping each item in its own conditional statement, which seems cumbersome.

In the past, I would have achieved this using Vanilla JS or JQuery with a simple getElementByClass. But I am unsure if this approach translates directly to React.

Could someone provide guidance on the next steps?

Thank you in advance.

Answer №1

Suppose you have received all your data at once (for example, fetched from an API) and need to display only a specific portion of it, you can dynamically slice the source data array while keeping track of the current page within the component's state (assuming a page length of 5 items):


        const [data, setData] = useState([]),
            [page, setPage] = useState(0),
            maxPage = Math.ceil(data.length / 5),
            onNextPage = () => setPage((page + 1) % maxPage),
            onPrevPage = () => setPage((page + 5 - 1) % maxPage)
    
<Grid container>
        {
            data
                .slice(page * 5, 5 * (page + 1))
                .map((content, key) => (
                    <Grid item {...{key}}>
                        <Paper className="paper">{content}</Paper>
                    </Grid>
                ))
        }
    </Grid>
    

You may want to explore the following demo for a complete example (assuming you are using Material-UI to style your components):

//dependencies
                const { render } = ReactDOM,
                      { useState, useEffect } = React,
                      { Button, Paper, Grid, LinearProgress } = MaterialUI,
                      { get } = axios

                //paginated output, defaulting to 5 items per page
                const PaginatedBoard = () => {

                  //initialize states and event handlers
                  const [data, setData] = useState([]),
                        [page, setPage] = useState(0),
                        maxPage = Math.ceil(data.length / 5),
                        onNextPage = () => setPage((page + 1) % maxPage),
                        onPrevPage = () => setPage((page + 5 - 1) % maxPage)

                  //fetch source data upon component rendering
                  useEffect(() => get('https://api.nytimes.com/svc/topstories/v2/science.json?api-key=k9DaUAw5wUAei4J5WXRsy3EL988RADE3').then(({ data: { results } }) => setData(results.map(({ abstract }) => abstract)), [])

                  //return component's body
                  return data.length ?
                      (<div>    
                        <Grid container spacing="2" >
                          {
                              data
                                  .slice(page * 5, 5 * (page + 1))
                                  .map((content, key) => (
                                      <Grid item {...{key}}>
                                          <Paper className="paper">{content}</Paper>
                                      </Grid>
                                  ))
                          }
                        </Grid>
                                <div>
                                    <Button onClick={onPrevPage} disabled={!page}>&lt;Prev</Button>
                                    <Button onClick={onNextPage} disabled={page == Math.ceil(data.length / 5) - 1}>Next&gt;</Button>
                                </div>

                      </div>) : 
                      <LinearProgress style={{ margin:'70px', width:'50%' }} />
                }

                //render
                render (
                  <PaginatedBoard />,
                  document.getElementById('root')
                )
            
.grid {
                width: 70%;
                margin: auto;
            }

            .paper {
                width: 100px;
                height: 145px;
                overflow: hidden;
            }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><script src="https://unpkg.com/@material-ui/core@latest/umd/material-ui.development.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.1/axios.min.js"></script><div id="root"></div>

Answer №2

To incorporate a for loop in your React HTML grid display, follow these steps:

Firstly, create an array of the desired size (numPages):

let elements = new Array(numPages);

Next, place the following snippet close to the button on your page:

<div>
{elements.map((entry, i) => {
  let start = i * limit
  let end = start + limit

  let pageItems = children.slice(start, end)

  // Avoid adding redundant data for 'page 1'.
  if (end != limit) {
    return (<Grid gridContainerStyles={'grid-page__' + i} items={pageItems} />)
  }

  return ''
})}

</div>

Answer №3

Adjust the display of children based on your current page state.

const displayedPages = Array.from({ length: pages }); // generate a new array to map over
displayedPages.map((_, index) => {
  const DisplayedItems = children.slice(limit*index, limit*index + limit);
  <Grid gridContainerStyles={'grid-page__' + i} items={displayedItems} />
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilizing ReactStrap: a guide to retrieving the id of the chosen dropDownItem

In my code, I have a dropdownList component with various DropdownItems: <Dropdown isOpen={this.state.dropdownOpen[3]} toggle={() => { this.toggle(3); }} > <DropdownToggle className="my-dropdown" car ...

Ways to access a function variable within an AJAX `done` function

This is the JavaScript function I am working with: $('.editable').change(function () { event.preventDefault(); var el_text = this.lastElementChild; var action = this.action; var method = this.method; var data = $(this).serialize(); ...

How can I reposition an image diagonally to a specific location using JavaScript in p5.js? Is there a method to display an image and then conceal it at a chosen location in p5.js?

Is there a way to move the third image diagonally until it intersects with the two images? var pic1; var pic2; var pic3; let posX=0 let posY=0 const rightwall=350; function preload(){ pic1=loadImage("5.png") pic2=loadImage("iron.jpg&qu ...

Is there a way to utilize variables in useEffect without including them in the dependency array?

Currently, I am dealing with an objectList and a size variable in my React component. const [objectList, setObjectList] = useState([]); // this array will be populated elsewhere const [size, setSize] = useState([props.width, props.height]); // the size may ...

When utilizing styled-jsx alongside postcss, experiencing issues with styles failing to reload or rebuild

I'm currently using postcss in conjunction with styled-jsx. In my setup, I have multiple CSS files that I'm importing using the @import directive within the _app.js file. Everything seems to work smoothly, except when I modify any of the CSS file ...

Is it compulsory for all pages to be built with react?

I am diving into the world of web development by creating my own website from scratch using React and Node.js with Next.js. I'm curious if it's possible to build certain sections, like the registration page, without using React. I wonder if optin ...

Tips for automatically refreshing a Next.js application following an update in an external library

I have a monorepo containing two applications: The first is a Next.js web app The second is a UI library using Tailwind CSS and Microbundle Currently, the only way I can get the web app to recognize changes made in the UI library is by following these st ...

Can a function be passed to the URL field in an AJAX request?

Can a function be passed to the url field in an ajax call? I am looking to dynamically change the url being used in the ajax call. function generateURL(){} $.ajax({ url: generateURL, context: document.body, success: function(){ $(this).addCla ...

Utilize a Vue.js filter on the v-model within an input element

Seeking assistance! I successfully created a directive that wraps the Jasny Bootstrap Plugin, specifically focusing on the input mask feature! Additionally, I have developed a custom filter using moment to format date fields! The date format received fro ...

Exploring type definition for function arguments in TypeScript and React

There is a high-order component (HOC) designed to store the value of one state for all input and select elements. The output function accepts arguments ({text: Component, select: Component}). An error is displayed while typing an argument: TS2322: Type &ap ...

jQuery Datatables have trouble accessing specific row information when the table is set to be responsive

Currently, I'm utilizing the jQuery DataTables plugin along with the responsive addon to dynamically display and hide columns based on the size of the browser window. One of the columns is labeled as Actions, which permits users to edit a record by c ...

The sidebar.querySelector method is not working as expected

Attempting to assign an 'active' class to the clicked 'nav-link' element in order for it to stay active on the next page the user navigates to. Encountering an issue with sidebar.getElementsByClassName is not a function showing up in t ...

Having trouble inserting an image using Vue?

I am having trouble understanding why only the first image loads, while the others do not. 1. <img :src="require('../assets/batatas.jpg')" :alt="item.title" /> 2. <img :src="'../assets/batatas.jpg'" ...

Tips for Angular JS Single Page Applications: Implementing Angular Controllers to Invoke Angular Services

Currently, I'm in the process of building a Node.js Application using Angular.js and Express.js. My goal right now is to populate a list with customer names and addresses by using this code snippet: var mylist = new generic.list(); mylist.add({name ...

Encountering challenges with the search and filtering features

I'm having some trouble with the search and filter features I'm creating. They work fine initially, but once I enter a search query in the input field, the results show up as expected. However, if I delete the query or enter a different one, the ...

Setting ng-click on a custom element directive in Angular 1.x: A guide

Within this code, I have assigned ng-click to a custom element directive with the expectation that clicking the rendered text would trigger an alert saying "Worked from directive!" However, the functionality does not seem to be working as intended. Althou ...

React-built NPM website fails to compile

After successfully running my website created with ReactJS on my local machine, I encountered an error when trying to build it using npm run build. The error message received was: > react-snap � pageerror at /personal-site/: SyntaxError: Unexpected ...

Several features - Second function malfunctioning

The initial inquiry is effective. However, the subsequent one is encountering issues as it is failing to confirm if an email contains the "@" symbol. My attempted solution involved reordering the functions related to email validation. <body onload="ch ...

How can I move a complete range of values up using the Google Sheets API in Node.JS?

I'm working with a Google Spreadsheet that is being accessed and modified by a Node.JS app. There's a specific situation where I need to shift an entire range up (moving A3:D up by one cell), but due to my limited experience with the Google Shee ...

JavaScript ECMAScript 6 - WARNING: "Decorators can only be applied to a class when exporting"

In ECMAScript 6, I am attempting to export a function so that I can import it and utilize it in other files for the sake of writing DRY code. However, an error message is appearing: You can only use decorators on an export when exporting a class (16:0) ...