3
\$\begingroup\$

I've published my first react project for pagination purposes. It's likely I'm making mistakes or there are any improvements to my code. I'd appreciate if anyone has any offers.

jQuery(document).ready(function($){

 /*
    Simple project to implementing pagination with React
    Developer: Alex Jolig

    Licence:MIT
    Source:https://github.com/alexjolig/react-pagination-without-jsx
    Contact me if you need to: alex.jolig@gmail.com

 */

 class ImageGallery extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
        posts: [], //However its not relevant in this sample but I named the array posts. feel free to name it as you wish
        currentPage: 1,
        postsPerPage: 5
    };
    this.handleClick = this.handleClick.bind(this);
    this.changePage = this.changePage.bind(this);
  }

  //put AJAX request in componentDidMount() method
  componentDidMount() {

    $.ajax({
      url: "generated.json",
      dataType: 'json',
      cache: false,
      success: function(data) {
        this.setState({posts: data});
        console.log(data);
      }.bind(this),
      error: function(xhr, status, err) {
        console.error("", status, err.toString());
      }.bind(this)
    }); 
  }

    //Handle click on page number list
    handleClick(event) {
        this.setState({
          currentPage: Number(event.currentTarget.id) //using event.target would reference to child tag (a). So use event.currentTarget 
        }); 
    }

    //Handle next and previous buttons
    changePage(event) {
        let newPage = 1;
        if(event.currentTarget.id === 'p-page') {
            newPage = this.state.currentPage > 1 ? this.state.currentPage - 1 : 1;
            this.setState({
              currentPage: newPage
            });
        }
        else {
            let pageCount = this.state.posts.length / this.state.postsPerPage;          
            newPage = this.state.currentPage < pageCount ? this.state.currentPage + 1 : pageCount;
            this.setState({
              currentPage: newPage
            });         
        }
    } 

    render() {

        const { posts, currentPage, postsPerPage } = this.state;

        // Logic for displaying current posts
        const indexOfLastPost = currentPage * postsPerPage;
        const indexOfFirstPost = indexOfLastPost - postsPerPage;
        const currentPosts = posts.slice(indexOfFirstPost, indexOfLastPost);        

        const renderPosts = currentPosts.map((post, index) => {
            return React.createElement('li', {key: post.index},
              React.createElement('h2', {}, post.name),
              React.createElement('a', {href: post.phone}, post.phone)
            )
        });     

        // Logic for displaying page numbers
        const pageNumbers = [];
        for (let i = 1; i <= Math.ceil(posts.length / postsPerPage); i++) {
          pageNumbers.push(i);
        }

        const prevPage = React.createElement(
            'li', { className: 'page-item',
                    key:'p-page',
                    id: 'p-page',
                    onClick: this.changePage
                },
            React.createElement('a', {  className: 'page-link',
                                        href: '#'
                                    }, 'Previous'
            )
          );

        const nextPage = React.createElement(
            'li', { className: 'page-item',
                    key:'n-page',
                    id: 'n-page',
                    onClick: this.changePage
                },
            React.createElement('a', {  className: 'page-link',
                                        href: '#'
                                    }, 'Next'
            )
          );          

        const renderPageNumbers = pageNumbers.map(number => {
          return React.createElement(
            'li', { className: 'page-item' + (currentPage === number ? ' active' : '') ,
                    key:number,
                    id: number,
                    onClick: this.handleClick
                },
            React.createElement('a', {  className: 'page-link',
                                        href: '#'
                                    }, number
            )
          );
        }); 

        //NOTE: return elements as array is added in react 16+
        return [
                React.createElement('div', {key: 'a', className: 'row'},
                    React.createElement('ul', {key:'a'}, renderPosts)
                ),
                React.createElement('div', {key: 'b', className: 'row'},
                                        React.createElement('ul', {className: 'pagination',key: 'b'}, 
                                        prevPage,
                                        renderPageNumbers,
                                        nextPage)   
                )                   
            ];
    }
 }

    ReactDOM.render(
        React.createElement(ImageGallery, null),
        document.getElementById('root')
    );
});
\$\endgroup\$
2
\$\begingroup\$

I recommend you to use JSX and build tools because they are totally awesome!

People use npm and bundlers (like Webpack) because loading each library separately makes the page significantly slower. Let me show you an extreme example. Feel free to take a peek at the source code. And that's not to mention that it's simpler to update my libraries using npm.

JSX can help you effortlessly construct the element tree in React. You're missing out a lot if you avoid JSX!

You can create an alias for React.createElement to make your code more readable.

const h = React.createElement;

//NOTE: return elements as array is added in react 16+

You're right. Did you know that React 16 also has a cooler feature?

If you used Fragments, you wouldn't need to add keys to the two divs you rendered in the render() method.

Here's the improved code:

return h(React.Fragment, null,
    h("div", { className: "row" },
        h("ul", null, renderPosts)
    ),
    h("div", { className: "row" },
        h("ul", { className: "pagination" }),
        prevPage,
        renderPageNumbers,
        nextPage
    )
)

You don't need to pass null as the second parameter here:

ReactDOM.render(
    React.createElement(ImageGallery, null),
    document.getElementById("root")
);
ReactDOM.render(h(ImageGallery), document.getElementById("root"))

You don't need to use jQuery(document).ready when you've already put your <script> tags under the container element.

The React community prefers using fetch and axios to fire AJAX requests because:

  • fetch is a Promise-based API for fetching resources, it is built in every major web browser out there.
  • axios is a small library that does only one thing and does it well, as opposed to jQuery which tries to be the library to do everything web-related.

Two last things:

  • Fix indentation. Or use Prettier and forget about it completely.
  • Remove all of the comments in your code.
\$\endgroup\$
  • 1
    \$\begingroup\$ Thanks for the heads ups. I'll try changing AJAX request to one of your offers. But the reason I wanted to do it without JSX is that I don't want to have to work with npm and stuffs when I'm going to use just a small component like this in a single page. I couldn't find any ways to use JSX without using npm. \$\endgroup\$ – Alex Jolig Jun 11 '18 at 4:47
  • 1
    \$\begingroup\$ You are right, if you are only using React for a small component on a large non-React web app then using JSX and build tools only adds overhead. And no, I am not giving you any heads up! ;P \$\endgroup\$ – continued- Jun 11 '18 at 13:03
  • \$\begingroup\$ I've published the professional version of my pagination and used your ideas. Thank you. Professional pagination using react \$\endgroup\$ – Alex Jolig Jun 13 '18 at 7:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.