如何在React组件中创建一个搜索、过滤和分页组件

615 阅读5分钟

我在一年前写了《如何在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密钥应该出现在你的仪表板上。

Web-capture_4-6-2022_184858_countryapi.io--1-

接下来,我们将用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。不要忘记点击关注按钮。

编码愉快!