Infinite reagent scroll

So, I have a list of 5k elements. I want to show them in parts, say, each part is 30 items. The list of items is in a component state. Each element is an object taken from the API. It has properties on which I have to make an API call. In parts to avoid huge loading times. So here is what I still have (simplified):

let page=1;

class GitHubLists extends Component {
    constructor(props) {
        super(props);

        this.state = {
            repos: [],
            contributors: []
        }
    }
    componentDidMount() {
      window.addEventListener('scroll', this.handleScroll);
      axios.get(org)
        .then(res => setState({contributors: res})
    }
     handleScroll() {
        page++;
    }
    componentWillUnmount() {
        window.removeEventListener('scroll', this.handleScroll);
    }
    render() {
        const contributors = this.state.contributors.slice(0,30*page).map(contributor =>
            <li key={contributor.id}>{contributor.login} {contributor.contributions}<a href={contributor.url}>View on GitHub</a></li>
        );
        return (
            <div onScroll={this.handleScroll}>{contributors}</div>
        )
    }
}
Run codeHide result

As I said, each element (the contributor in this case) has properties whose values ​​are links for API calls. 3 to be exact. On each of them I need to make an API call, count the elements inside the response and display them.

+4
source share
3

, GIST, , , .

class ItemsApp extends React.Component {
  constructor() {
    super();
    this.state = {
      items: ['a','b','c','d','e','f','g','h','i','j','k','2','4','1','343','34','a','b','c','d','e','f','g','h','i','j','k','2','4','1','343','34','a','b','c','d','e','f','g','h','i','j','k','2','4','1','343','34','33'],
      currentPage: 1,
      itemsPerPage: 30
    };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(event) {
    this.setState({
      currentPage: Number(event.target.id)
    });
  }

  render() {
    const { items, currentPage, itemsPerPage } = this.state;

    // Logic for displaying current items
    const indexOfLastItem = currentPage * itemsPerPage;
    const indexOfFirstItem = indexOfLastItem - itemsPerPage;
    const currentItems = items.slice(indexOfFirstItem, indexOfLastItem);

    const renderItems = currentItems.map((item, index) => {
      return <li key={index}>{item}</li>;
    });

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

    const renderPageNumbers = pageNumbers.map(number => {
      return (
        <li
          key={number}
          id={number}
          onClick={this.handleClick}
        >
          {number}
        </li>
      );
    });

    return (
      <div>
        <ul>
          {renderItems}
        </ul>
        <ul id="page-numbers">
          {renderPageNumbers}
        </ul>
      </div>
    );
  }
}


ReactDOM.render(
  <ItemsApp />,
  document.getElementById('app')
);

https://codepen.io/anon/pen/jLZjQZ?editors=0110

, itemsPerPage , 30 .

, =)

0

react-virtualized ( 6.8k), .

1000 Infinite Loader.

, .

API rowRenderer overscanRowCount . ( List)

+2

, - , . API. ( ) . :

let unorderedContributors = [];
let contributors = [];

class GitHubLists extends Component {
    constructor(props) {
        super(props);

        this.state = {
            repos: [],
            contributors: [],
            currentPage: 1,
            itemsPerPage: 30,
            isLoaded: false
        };
        this.handleClick = this.handleClick.bind(this)
    }
    componentWillMount() {
    //get github organization
        axios.get(GitHubOrganization)
        .then(res => {
            let numberRepos = res.data.public_repos;
            let pages = Math.ceil(numberRepos/100);
            for(let page = 1; page <= pages; page++) {
            //get all repos of the organization
                axios.get(`https://api.github.com/orgs/angular/repos?page=${page}&per_page=100&${API_KEY}`)
                .then(res => {
                    for(let i = 0; i < res.data.length; i++) {
                        this.setState((prevState) => ({
                            repos: prevState.repos.concat([res.data[i]])
                          }));
                    }
                })
                .then(() => {
                //get all contributors for each repo
                    this.state.repos.map(repo =>
                    axios.get(`${repo.contributors_url}?per_page=100&${API_KEY}`)
                    .then(res => {
                        if(!res.headers.link) {
                            unorderedContributors.push(res.data);
                        }
                            //if there are more pages, paginate through them
                        else {
                            for(let page = 1; page <= 5; page++) { //5 pages because of GitHub restrictions - can be done recursively checking if res.headers.link.includes('rel="next"')
                            axios.get(`${repo.contributors_url}?page=${page}&per_page=100&${API_KEY}`)
                            .then(res => unorderedContributors.push(res.data));
                            }
                        }
                    })
                    //make new sorted array with useful data
                    .then(() => {contributors = 
                        _.chain(unorderedContributors)
                        .flattenDeep()
                        .groupBy('id')
                        .map((group, id) => ({
                            id: parseInt(id, 10),
                            login: _.first(group).login,
                            contributions: _.sumBy(group, 'contributions'),
                            followers_url: _.first(group).followers_url,
                            repos_url: _.first(group).repos_url,
                            gists_url: _.first(group).gists_url,
                            avatar: _.first(group).avatar_url,
                            url: _.first(group).html_url
                          }))
                        .orderBy(['contributions'],['desc'])
                        .filter((item) => !isNaN(item.id))
                        .value()})
                    .then(() => 
                                this.setState({contributors, isLoaded: true})
                        )
                    )
                })
            }
        })          
    }
    handleClick(event) {
        this.setState({currentPage: Number(event.target.id)})
    }
    render() {
        const { contributors, currentPage, contributorsPerPage } = this.state;


        //Logic for displaying current contributors
        const indexOfLastContributor = currentPage * contributorsPerPage;
        const indexOfFirstContributor = indexOfLastContributor - contributorsPerPage;
        const currentContributors = contributors.slice(indexOfFirstContributor, indexOfLastContributor);

        const renderContributors = currentContributors.map((contributor, index) => {
            return <li key={index}>{contributor}</li>;
        });

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

        const renderPageNumbers = pageNumbers.map(number => {
            return (
                <li 
                key={number}
                id={number}
                onClick={this.handleClick}
                >
                {number}
                </li>
            );
        });

        return (
            <div>
                <ul>
                    {renderContributors}
                </ul>
                <ul id="page-numbers">
                    {renderPageNumbers}
                </ul>
            </div>
        );

    }
}
Hide result

, , ( API : followers_url, repos_url gists_url)?

0

Source: https://habr.com/ru/post/1684031/


All Articles