杭州电子商务研究院

React 中的分页 API 请求

2020-08-27 08:00飞浪

介绍

网络上充斥着 API 请求,大多数情况下,获取的数据只有在需要时才会加载(分页),以确保流畅的用户体验。这是通过从外部源(如 API)获取数据来实现的。本指南重点介绍如何使用 Hacker News API 在 React 中实现分页。喝杯咖啡 ☕,开始编程吧。

设置 React

打开终端并运行以下命令来设置您的 React 项目。您也可以通过访问https://react.new通过 CodeSandbox 获取完全配置的 React 环境。

      npx create-react-app my-app
  cd my-app
  npm start
    

在浏览器中打开 localhost:3000。你应该会看到一个动画的 React 徽标。

API 端点和数据结构

用于获取数据的 API 端点是https://hn.algolia.com/api/v1/search。此端点接受搜索查询和页码等参数。使用startups查询参数向此端点发出请求,URL 应如下所示:https://hn.algolia.com/api/v1/search ?query=startups 。成功的请求应返回以下结果:

      {
	hits: [
		{
			created_at: '2015-04-07T12:07:10.000Z',
			title:
				"What I'd tell myself about startups if I could go back 5 years",
			url:
				'http://www.talkingquickly.co.uk/2015/04/what-id-tell-myself-about-startups/',
			author: 'vinnyglennon',
			points: 865,
			story_text: null,
			comment_text: null,
			num_comments: 273,
			story_id: null,
			story_title: null,
			story_url: null,
			parent_id: null,
			created_at_i: 1428408430,
			relevancy_score: 5955,
			_tags: ['story', 'author_vinnyglennon', 'story_9333330'],
			objectID: '9333330',
			_highlightResult: {
				title: {
					value:
						"What I'd tell myself about <em>startups</em> if I could go back 5 years",
					matchLevel: 'full',
					fullyHighlighted: false,
					matchedWords: ['startups'],
				},
				url: {
					value:
						'http://www.talkingquickly.co.uk/2015/04/what-id-tell-myself-about-<em>startups</em>/',
					matchLevel: 'full',
					fullyHighlighted: false,
					matchedWords: ['startups'],
				},
				author: {
					value: 'vinnyglennon',
					matchLevel: 'none',
					matchedWords: [],
				},
			},
		},
                 ........ 
	],
	nbHits: 136242,
	page: 0,
	nbPages: 50,
	hitsPerPage: 20,
	exhaustiveNbHits: false,
	query: 'startups',
	params:
		'advancedSyntax=true&analytics=true&analyticsTags=backend&query=startups',
	processingTimeMS: 7,
}
    

此响应中最重要的部分是nbPages(页数)、hitsPerPage(每页结果数)和hits数组,其中包含数据本身。花点时间自己检查一下数据。

提出请求

现在您已经清楚地了解了响应数据,请使用 fetch API 将 hits 数组存储在状态中,如下面的代码片段所示。

      import React, { useState } from 'react';

const NewsCard = (props) => {
	return (
		<div style={{ padding: '20' }}>
			<a href={props.url}>
				{props.title} by {props.author}
			</a>
		</div>
	);
};

function App() {

    const [hits, setHits] = useState([]);
    const [isLoaded, setisLoaded] = useState(false);
    const [query, setQuery] = useState('startups'); 

    const URL = `https://hn.algolia.com/api/v1/search?query=${query}`;

    const handleFetch = () => {
		fetch(URL)
			.then(response => response.json())
			.then(body => {
				setData([...body.hits]);
			})
			.catch(error => console.error('Error', error));
	};

return (
    <div>
         <label>Search</label>
        <input type="text" onChange={(event) => setQuery(event.target.value)} />
        <button onClick={handleFetch}>Get Data</button>

			{isLoaded ? (
				hits.map((item) => {
					return (
						<NewsCard
							url={item.url}
							title={item.title}
							author={item.author}
							key={item.objectID}
						/>
					);
				})
			) : (
				<div></div>
			)}    
    </div>
);
  
}

export defailt App;
    

上述代码从输入元素获取查询值并将其存储在状态中。单击按钮时,将向端点发出请求,然后端点将呈现包含 hits 数组中的故事标题的 URL 列表。

实现分页

在您从 API 端点收到的响应中,请注意有一个值显示可用的页面数。这有助于了解页面选项卡的数量或要发出的最大请求数。从头开始处理分页可能非常耗时且令人沮丧,但幸运的是,有一个很棒的库可以轻松实现这一点:React-Paginate。

运行以下命令将 React-Paginate 添加到您的依赖项。

      npm install react-paginate --save
    
      import React, { useState } from 'react'; 
import ReactPaginate from 'react-paginate'; #New

const NewsCard = (props) => {
	return (
		<div style={{ padding: '20' }}>
			<a href={props.url}>
				{props.title} by {props.author}
			</a>
		</div>
	);
};

function App() {

    const [hits, setHits] = useState([]);
     const [pageCount, setPageCount] = useState(1); #New
    const [isLoaded, setisLoaded] = useState(false);
    const [currentPage, setcurrentPage] = useState(0); #New
    const [query, setQuery] = useState('startups'); 

    const URL = `https://hn.algolia.com/api/v1/search?query=${query}&page=${currentPage}`;

    const handleFetch = () => {
		fetch(URL)
			.then(response => response.json())
			.then(body => {
				setData([...body.hits]);
                                setPageCount(body.nbPages); #New
                                setisLoaded(true); #New
			})
			.catch(error => console.error('Error', error));
	};

      #New
	const handlePageChange = (selectedObject) => {
		setcurrentPage(selectedObject.selected);
		handleFetch();
	};

return (
    <div>
         <label>Search</label>
        <input type="text" onChange={(event) => setQuery(event.target.value)} />
        <button onClick={handleFetch}>Get Data</button>

			{isLoaded ? (
				hits.map((item) => {
					return (
						<NewsCard
							url={item.url}
							title={item.title}
							author={item.author}
							key={item.objectID}
						/>
					);
				})
			) : (
				<div></div>
			)}    
                       #New
			{isLoaded ? (
				<ReactPaginate
					pageCount={pageCount}
					pageRange={2}
					marginPagesDisplayed={2}
					onPageChange={handlePageChange}
					containerClassName={'container'}
					previousLinkClassName={'page'}
					breakClassName={'page'}
					nextLinkClassName={'page'}
					pageClassName={'page'}
					disabledClassNae={'disabled'}
					activeClassName={'active'}
				/>
			) : (
				<div>Nothing to display</div>
			)} 

    </div>
);
  
}

export defailt App;
    

添加这些 CSS 类可以使分页选项卡看起来更加美观。

      .container{
    display: flex;
    list-style: none;
}

.page{
	padding: 10px;
    border: 1px solid #dcdcdc;
    border-radius: 6px;
    margin-right: 10px;
    cursor: pointer;
}

.disabled{
    cursor: not-allowed;
    
}

.active{
	border: 2px solid #000;
    font-weight: bold;
}

.previous{
    padding: 10px;
    border-radius: 6px;
    margin-right: 10px;
    cursor: pointer;
}

.break{
    padding: 10px;
}

.next{
    padding: 10px;
    border-radius: 6px;
    margin-right: 10px;
    cursor: pointer;
}
    

理解实施

当前页面被置于状态中,每次用户单击新页面按钮时都会更新。React-Paginate 将回调函数作为名为onPageChange的 prop ,该函数将包含所选页面的对象作为名为selected 的属性。在负责该回调函数 ( handlePageChange ) 中,当前页面的状态会更新,并触发网络请求。

道具:

  1. pageCount(必需)属性指的是所需的页面总数。
  2. pageRangeDisplayed(必需)prop 表示显示的页面范围。
  3. marginPagesDisplayed(必需)表示要显示的页边距的页数。

结论

就是这样!这是在 React 中实现分页的最简单方法。我建议你阅读文档以了解更多信息:React Paginate。你也可以在 Twitter 上关注我@DesmondNyamador。

曝光28367浏览1542