在我的程序中,我有各种各样的卡片都放在屏幕上,上面有人物的图片和有关该人物的信息。我正在从API中提取所有这些信息,并负责执行客户端分页以一次仅在屏幕上显示几张卡片。
这是我的代码:
genCard = () => {
const { isLoaded, items, currentPage, totalNumberPages, recordsPerPage } = this.state;
if (isLoaded) {
let returnCard = [];
let i;
for(i = currentPage; i < recordsPerPage; i++) {
returnCard.push(<Card key={items[i].id} cardName={items[i].name} imgSrc={items[i].image} birthYear={items[i].birth_year}/>);
}
return returnCard;
}
return null;
};
handlePageClick = (data) => {
let selected = data.selected;
let offset = Math.ceil(selected * this.props.perPage);
this.setState({
})
};
如您所见,我使用的是for循环,一次只能在屏幕上显示10个项目(卡片)。我想做的是当您单击另一页时,我希望它重新呈现并在屏幕上显示其他卡片。
那么,我该怎么做呢?如何将状态设置为您单击的页面,以便将正确的卡片呈现在屏幕上?
在此先感谢您的帮助。希望这是有道理的。
答案 0 :(得分:1)
更新:除了下面的JSFiddle链接之外,还在此处添加代码段。
function Card(props) {
return <div>I'm card {props.id}</div>
}
class Cards extends React.Component {
constructor(props) {
super(props)
this.state = {
isLoaded: false,
items: [1,2,3,4,5,6,7,8,9,10, 11, 12, 13, 14, 15],
currentPage: 1,
recordsPerPage: 5,
itemStartIndexOnPage: 0,
tempCount: 0
}
}
getCards = () => {
const {items, itemStartIndexOnPage, recordsPerPage} = this.state;
const itemsForThisPage = items.slice(itemStartIndexOnPage, itemStartIndexOnPage + recordsPerPage);
let cards = itemsForThisPage.map((item, i) => <Card key={item} id={item} {...item} />)
return cards;
}
handlePageClick = (data) => {
let selected = data;
let offset = Math.ceil((selected - 1) * this.state.recordsPerPage);
this.setState({
currentPage: selected,
itemStartIndexOnPage: offset
})
}
render() {
return (
<div>
Page No: {this.state.currentPage}
{this.getCards()}
<button onClick={() => this.handlePageClick(1)}>Page 1</button>
<button onClick={() => this.handlePageClick(2)}>Page 2</button>
<button onClick={() => this.handlePageClick(3)}>Page 3</button>
</div>
)
}
}
ReactDOM.render(<Cards />, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
如果您正在寻找的话,我已经写了这个snippet。
setState
重新渲染组件树。因此,在单击分页按钮时调用handlePageClick
,然后可以在getCards()
函数中调用render()
,该函数将更新组件中的卡。
如果需要在页面单击时从API端点获取项的子集,则可以使handlePageClick
异步,并在setState
之后或await
中调用then
。如果您要一次获取所有数据,则可以在componentDidMount
中进行操作并存储在状态中。
答案 1 :(得分:0)
您可以在handlePageClick中添加以下内容
this.setState({ currentPage: selected })
并如下更改genCard
const startIndex = currentPage * recordsPerPage
for(i = startIndex i < startIndex + recordsPerPage; i++) {
returnCard.push(<Card key={items[i].id} cardName={items[i].name}
imgSrc={items[i].image} birthYear={items[i].birth_year}/>);
}
答案 2 :(得分:0)
好吧,说实话,您可以访问状态时似乎已经能够进行足够的反应,并且您正在将某些项目渲染为子项,所以目前阻止您定义onClick
的原因是处理程序将调用类定义的函数(使用您看似使用的类属性)还是通过将方法绑定到构造函数中?
是否只是您缺少寻呼机,以便您实际上可以委托事件?
我认为Sai Sandeep Vaddis answer已经为您提供了有关如何处理分页数据的一些信息,这是我要添加的唯一一件事,即如何构造多个组件以使其在整个应用程序中可重复使用。 / p>
现在,请记住,关于您的宏伟设计,我没有任何线索,并且您显示的代码(除了您的循环并没有真正开始正确之外)似乎还在工作
const { Component } = React;
// overly basic pager
const Pager = ({ page, pageSize, itemCount, onPageChange }) => {
const totalPages = Math.ceil( itemCount / pageSize );
const children = [];
for (let i = 0; i < totalPages; i++) {
children.push( <span key={ i } onClick={ () => onPageChange(i) } className={ classNames( 'page-item', { selected: i === page } ) }>{ i + 1 }</span> );
}
return <div className="pager">{ children }</div>;
};
// a component to keep a local state (current page state, and all the items it holds)
class PagedList extends Component {
constructor() {
super();
this.state = {
page: 0
};
this.changePage = this.changePage.bind( this );
}
changePage( targetPage ) {
this.setState( { page: targetPage } );
// this could theoretically inform any parent that the page has changed
// in case this should be tracked from the parent (in which case having
// the page as state doesn't really make sense anymore, it was just a
// quick way to enable paging for already retrieved data
}
render() {
const { page = 0 } = this.state;
// some default settings on this.props (can be done with getDerivedProps or getDefaultProps as well)
const { items, pageSize = 10, component = props => JSON.stringify(props) } = this.props;
// no items yet, wait for the next render I suppose
if (!items) {
return <div>No items available</div>;
}
// render pager / current page items / pager
return <div>
<Pager page={ page } pageSize={ pageSize } itemCount={ items.length } onPageChange={ this.changePage } />
{ items.slice( page * pageSize, (page * pageSize) + pageSize ).map( item => React.createElement( component, {...item, key: item.id } ) ) }
<Pager page={ page } pageSize={ pageSize } itemCount={ items.length } onPageChange={ this.changePage } />
</div>
}
}
// very basic component displaying the name of the breed
const BreedItem = ({ name }) => <div>{ name }</div>;
// component that will load a random image when originally loaded
// could probably use a flag that says if it's still mounted before updating the state
// but, it's simply good to be aware of it :)
class BreedCard extends Component {
constructor() {
super();
this.state = {
};
}
componentDidMount() {
const { name } = this.props;
fetch( `https://dog.ceo/api/breed/${name}/images/random` )
.then( response => response.json() )
.then( data => this.setState( { image: data.message } ) );
}
render() {
const { name } = this.props;
const { image } = this.state;
return <div className="card">
<BreedItem name={ name } />
{ image ? <img src={ image } alt={ name } /> : <span>loading image</span> }
</div>;
}
}
// gets the items from the api (all at once to be fair)
// and then renders them in a PagedList
// doesn't really have a clue about what page it in, just decides on
// - pageSize
// - data
// - component to render
class BreedList extends Component {
constructor() {
super();
this.state = {
items: []
};
}
componentDidMount() {
fetch( 'https://dog.ceo/api/breeds/list/all' )
.then( response => response.json() )
.then( data => this.setState( { items: Object.keys( data.message ).map( key => ({ id: key, name: key }) ) } ) );
}
render() {
const { items } = this.state;
return <PagedList pageSize={10} items={items} component={ BreedCard } />;
}
}
// lets get cracking then :)
const container = document.querySelector('#container');
ReactDOM.render( <BreedList />, container );
.page-item {
display: inline-block;
padding: 5px;
cursor: pointer;
border-radius: 5px;
}
.page-item:hover {
background: silver;
}
.selected {
background-color: blue;
color: white;
}
.pager {
border: solid black 1px;
display: flex;
flex-direction: row;
font-size: .8em;
}
.card {
display: inline-flex;
flex-direction: column;
align-items: center;
border: solid #a0a0a0 1px;
margin: 3px;
padding: 5px;
}
.card > img {
max-width: 320px;
max-height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script id="classnames" src="https://cdnjs.cloudflare.com/ajax/libs/classnames/2.2.5/index.js"></script>
<div id="container"></div>