所以我有一个5k元素列表。我想将它们分成几部分显示,每个部分都是30个项目。项目列表处于组件的状态。每个项目都是从API中获取的对象。它具有我必须进行API调用的属性。按部件,避免巨大的加载时间。所以这就是我到目前为止(简化):
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>
)
}
}
就像我说的每个项目(在这种情况下是贡献者)具有属性,其值是API调用的链接。 3准确地说。在每一个上面,我需要进行API调用,计算响应中的项目并显示它们。
答案 0 :(得分:2)
您可以使用react-virtualized(6.8k星),它是专为此目的而设计的。
Here is an official example包含1000个元素的列表或here with a Infinite Loader。
我写了一个更简单的实例here,您可以在其中修改代码。
对于您的问题,您需要在rowRenderer
中进行API调用,并使用overscanRowCount
来预取行。 (docs of the List component)
答案 1 :(得分:0)
我做了一个简单的分页,改编自我已经使用过的另一个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 次。
我希望它有帮助=)
答案 2 :(得分:0)
好的,关于我如何编写应用程序肯定有问题。它不是在等待所有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>
);
}
}
&#13;
如何修复它以便状态设置一次然后我可以从状态渲染贡献者(并使用属性值进行API调用:followers_url,repos_url和gists_url)?