我在一年前写了《如何在React中搜索和过滤组件》这篇文章。
如果你正在构建一个React应用程序,你希望你的用户能够搜索并获得准确的结果。
如果你从API中获取数据,他们需要能够轻松找到东西。
这里@sprucekhalifa向你展示了如何在React中搜索和过滤组件。https://t.co/yKsaUqjGY9
- freeCodeCamp.org (@freeCodeCamp)2021年6月5日
从那时起,很多事情都发生了变化。我们在教程中使用的API已经停止工作了,所以在这篇文章中,我们将重现我们之前的例子,同时也为我们的组件引入分页功能。
本教程使用了React.js,所以你需要对React和JavaScript有基本的了解才能跟上。本教程还假定你已经阅读了之前的文章《如何在React中搜索和过滤组件》。
开始学习
为了获得本教程的国家数据,我们将使用CountryAPI.io的国家API。
我们需要一个API密钥来使用该API。要得到你的API密钥,请到CountryAPI.io并创建一个账户。你的API密钥应该出现在你的仪表板上。

接下来,我们将用Create React App创建一个新的React应用程序。要做到这一点,在你的终端运行以下程序。
# Run this to use npm
npx create-react-app search-app
# Or run this to use yarn
yarn create react-app search-app
cd my-app
npm start
# Or with yarn
yarn start
像往常一样,对于实时预览,我们将使用Codepen来显示我们所有的例子。
如何获取数据
为了获取数据,我们必须对https://countryapi.io/api/all 端点进行GET调用,同时提供我们的API密钥。在我们之前创建的React应用程序的src > App.js 文件中,删除所有现有的代码,并将其替换为以下内容。
import { useState, useEffect } from "react";
import "./App.css";
function App() {
const [error, setError] = useState(null);
const [loaded, setLoaded] = useState(false);
const [items, setItems] = useState([]);
useEffect(() => {
const request_headers = new Headers();
const api_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxx";
request_headers.append("Authorization", `Bearer ${api_key}`);
request_headers.append("Content-Type", "application/json");
const request_options = {
method: "GET",
headers: request_headers,
};
fetch("https://countryapi.io/api/all", request_options)
.then((res) => res.json())
.then(
(result) => {
setLoaded(true);
setItems(result);
},
(error) => {
setLoaded(true);
setError(error);
}
);
}, []);
console.log(items)
if (error) {
return <>{error.message}</>;
} else if (!loaded) {
return <>loading...</>;
} else {
return (
//
);
}
}
export default App;
我们上面所做的就是使用JavaScript fetch API向我们的端点发出GET请求,然后使用setState(result) ,将返回的数据存储在items 状态。
如何显示数据
接下来,我们需要显示API数据,这将是一个由我们的API返回的所有国家的列表。
为了制作一个列表,我们需要从我们返回的对象中的值生成一个对象数组。打开src > App.js 文件,添加以下代码。
import { useState, useEffect } from "react";
import "./App.css";
function App() {
const [error, setError] = useState(null);
const [loaded, setLoaded] = useState(false);
const [items, setItems] = useState([]);
useEffect(() => {
// fetch data
}, []);
const data = Object.values(items);
if (error) {
return <>{error.message}</>;
} else if (!loaded) {
return <>loading...</>;
} else {
return (
<div className="wrapper">
<ul className="card-grid">
{data.map((item) => (
<li key={item.alpha3Code}>
<article className="card">
<div className="card-image">
<img src={item.flag.large} alt={item.name} />
</div>
<div className="card-content">
<h2 className="card-name">{item.name}</h2>
// other card content
</article>
</li>
))}
</ul>
</div>
);
}
}
export default App;
通过添加一些CSS,上面的例子看起来就像下面的预览。
如何创建搜索组件
首先是创建一个输入字段,用户可以在这里输入他们的搜索查询。打开src > App.js ,进行如下编辑。
...
function App() {
const [query, setQuery] = useState("");
if (error) {
return <>{error.message}</>;
} else if (!loaded) {
return <>loading...</>;
} else {
return (
<div className="wrapper">
<div className="search-wrapper">
<label htmlFor="search-form">
<input
type="search"
name="search-form"
id="search-form"
className="search-input"
placeholder="Search for..."
onChange={(e) => setQuery(e.target.value)}
/>
<span className="sr-only">Search countries here</span>
</label>
</div>
...
</div>
);
}
}
export default App;
上面我们创建了一个输入字段,使用onChange 事件处理程序,只要输入字段的值发生变化,我们就使用useState 钩子将该值设置为query 。
接下来,我们需要使用query 来过滤从我们的API返回的数据。
const search_parameters = Object.keys(Object.assign({}, ...data));
function search(data) {
return items.filter(
(item) =>
search_parameters.some((parameter) =>
item[parameter].toString().toLowerCase().includes(query)
)
);
}
让我们把它分解一下。首先,我们创建了一个函数search() ,将我们的data 作为一个参数。结合Array.filter() 和Array.some() 方法,我们检查我们的搜索参数是否包括我们的查询值includes(query) 。
当然,我们可以硬编码我们的搜索参数。
const search_parameters = ["Capital", "Name", ...]
虽然这是最快的方法,但它并不适合未来(从API返回的数据可能会改变)--我发现这一点是很难的。因此,我们可以从API返回的data ,而不是硬编码,获得搜索参数。
const search_parameters = Object.keys(Object.assign({}, ...data));
最后,我们需要使用从search(data) 函数返回的新数据来建立我们的国家名单。打开App.js 文件,编辑我们之前创建的列表。
...
{search(data).map((item) => (
<li key={item.alpha3Code}>
<article className="card">
<div className="card-image">
<img src={item.flag.large} alt={item.name} />
</div>
<div className="card-content">
<h2 className="card-name">{item.name}</h2>
...
</div>
</article>
</li>
))}
添加了搜索功能后,现在的实时预览看起来像这样。
如何创建过滤器组件
过滤器通常用于通过特定的关键词来分组数据。在这个例子中,我们想按地区对数据进行分组。
同样,我们可以从数据中获取区域,而不是硬编码。
const filter_items = [...new Set(data.map((item) => item.region))];
在我们创建的搜索输入字段之后,添加过滤器用户界面--它是一个HTMLselect 输入字段。
...
const [filter, setFilter] = useState("");
...
<div className="select">
<select
onChange={(e) => setFilter(e.target.value)}
className="custom-select"
aria-label="Filter Countries By Region">
<option value="">Filter By Region</option>
{filter_items.map((item) => (
<option value={item}>Filter By {item}</option>
))}
</select>
<span className="focus"></span>
</div>
为了添加过滤器,我们必须修改search(data) 函数。因此,我们现在不是只返回我们搜索到的数据,而是返回数据作为我们的过滤器参数。
function search(items) {
return items.filter(
(item) =>
item.region.includes(filter) &&
search_parameters.some((parameter) =>
item[parameter].toString().toLowerCase().includes(query)
)
);
}
就这样--我们现在可以按地区过滤我们的国家。实时预览和完整的代码可以在Codepen上找到。
如何创建分页组件
分页不仅仅是减少网页上显示的项目列表,它还可以提高应用程序的性能,因为用户在加载页面时只需要下载少量的资源。
为了给我们的国家数据创建分页,我们将首先指定我们想在useState 中显示的项目数量。
const [paginate, setpaginate] = useState(8);
接下来让我们使用我们的paginate 值来更新我们的国家列表。
...
{search(data)
.slice(0, paginate)
.map((item) => (
<li key={item.alpha3Code}>
<article className="card">
<div className="card-image">
<img src={item.flag.large} alt={item.name} />
</div>
<div className="card-content">
<h2 className="card-name">{item.name}</h2>
...
</div>
</article>
</li>
))}
接下来我们需要创建一个函数,在这个函数中我们随时更新这个状态。
const load_more = (event) => {
setpaginate((prevValue) => prevValue + 8);
};
最后,让我们创建一个按钮,当点击时将调用load_more 函数。
<button onClick={load_more}>Load More</button>
同样,分页的预览可以在CodePen上找到。
结论
在这篇文章中,我们通过使用CountryAPI.io构建一个真实世界的应用程序,了解了如何在React中实现搜索、过滤和分页的功能。
如果你用它创造了一些精彩的东西,请随时在推特上发表,并标记我@sprucekhalifa。不要忘记点击关注按钮。
编码愉快!