React 搜索栏 让我们在 React 中构建一个搜索栏!

2025-05-24

React 搜索栏让我们在 React 中构建一个搜索栏!

本文的原始版本可以在这里找到。

我知道,我知道...另一个任务应用程序...

听我说完!我们将构建一个任务应用,它还能根据搜索查询实时过滤列表。听起来很复杂?其实并没有你想象的那么复杂,让我们开始吧!

开始之前先简单说明一下:
我将使用 Parcel 作为打包工具。它非常棒,而且
设置起来超级简单。我还有另一篇关于使用 Parcel 设置项目的文章
,里面会提供更多设置信息,所以如果我
在这里讲得太快,建议你先去这里看看。

设置我们的文件

首先,我们将创建目录并使用命令行进入。为此,请打开终端并导航到要放置项目的目录。到达那里后,使用以下代码行创建项目目录并进入。

mkdir search-tasks && cd $_
Enter fullscreen mode Exit fullscreen mode

现在我们进入了项目文件夹,需要使用 yarn 或 npm 初始化项目。在本项目中,我将使用 yarn,但 npm 的命令基本相同。

yarn init -y
Enter fullscreen mode Exit fullscreen mode

我们将直接使用该-y标志,以便它自动为我们配置。我们package.json很快就会进入并修改该文件。

现在我们有了一个package.json文件,我们应该创建index.htmlapp.js文件。你可以在终端中使用下面的代码行同时创建这两个文件。

touch index.html app.js
Enter fullscreen mode Exit fullscreen mode

接下来我们需要打开index.html文件进行编辑并将下面的代码放入其中:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Search To-Do App</title>
</head>
<body>
  <div id="app"></div>
  <script src="./app.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

将包添加到我们的项目

将包添加到我们的项目

接下来,我们需要在项目中安装必要的软件包。在本例中,这些软件包包括 React、React DOM、Parcel、Babel-Preset-env、Babel-Preset-React 和 Bulma。要将这些软件包添加到项目中,您可以使用 NPM 或 Yarn。我会提供这两种软件包的代码,您可以选择更合适的方式。

npm install react react-dom parcel babel-preset-env babel-preset-react bulma --save-dev

or

yarn add react react-dom parcel babel-preset-env babel-preset-react bulma
Enter fullscreen mode Exit fullscreen mode

这些是做什么的?

NPM 和 Yarn 是软件包管理器,允许您将预先编写的代码添加到项目中。这可以显著加快开发速度。下面简要介绍一下这两个软件包的功能。

  • React:一个加速开发的库(对于 React 教程来说这似乎很明显,对吧?)链接
  • React-DOM:一个允许 React 与浏览器中的 DOM 进行交互的库。链接
  • Parcel:无需配置的打包库。链接
  • Babel-preset-env:一个库,它告诉 Parcel 如何转换 ES6 代码,使其兼容各种浏览器。链接
  • Babel-preset-react:一个告诉 Parcel 如何处理 JSX 的库。链接
  • Bulma:一个使用 flexbox 布局且易于使用的 CSS 框架。链接

设置 package.json 和 .babelrc

在实际开始构建 React 项目之前,我们需要添加一个.babelrc文件来包含我们安装的 babel-presets。首先,使用以下代码创建文件:

touch .babelrc && open $_
Enter fullscreen mode Exit fullscreen mode

进入文件后,我们将添加以下代码以包含已安装的预设。

{
  "presets": ["env", "react"]
}
Enter fullscreen mode Exit fullscreen mode

设置好 .babelrc 文件后,我们需要将启动脚本添加到 package.json 文件中。打开该文件,在文件中添加以下代码:

"scripts": {
    "start": "parcel index.html"
},
Enter fullscreen mode Exit fullscreen mode

设置 app.js 文件

还在吗?太棒了!下一步是在app.js文件中设置一个组件。我们将使用状态来管理列表,因此需要使用类组件。首先,让我们导入构建应用所需的库。

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import 'bulma/bulma';
Enter fullscreen mode Exit fullscreen mode

然后我们可以创建一个 App 组件:

class App extends Component {
  render() {
    return(
      ...
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

然后我们需要确保组件渲染到 DOM。我们将使用 React DOM 来实现这一点。

ReactDOM.render(<App />, document.getElementById('app'));
Enter fullscreen mode Exit fullscreen mode

现在我们可以添加构造函数和状态了。我们将在状态中创建一个“list”数组。首先,我们将在其中填充一些项目,以便我们可以看到列表:

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      list: [
        "Go to the store",
        "Wash the dishes",
        "Learn some code"
      ]
    }
  }
  ...
}
Enter fullscreen mode Exit fullscreen mode

太棒了!现在我们在 App 组件的状态中已经有了列表,让我们来显示它。我使用的样式是 Bulma,但你可能用的是其他的。这完全没问题,你只需要相应地调整你的类即可。

class App extends Component {
  ...
  render() {
    return (
      <div className="content">
        <div className="container">
          <section className="section">
            <ul>
              {this.state.list.map(item => (
                <li key={item}>{item}</li>
              ))}
            </ul>
          </section>
        </div>
      </div>
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

上面的代码在做什么?

我们需要渲染列表。为此,我们使用了一些 Bulma 类来提供一些布局空间。最重要的部分是<ul>。首先,我们创建<ul>要在其中显示列表的 。然后,我们将使用花括号转义 JSX 代码,并使用名为 的 JavaScript 函数.map()。我们获取在状态中创建的列表this.state.list,并将其添加.map()到其末尾。然后,我们传递一个回调函数(在本例中使用箭头函数)来返回我们要显示的 JSX 代码。

函数.map()的工作原理与 a 类似,foreach因为它会循环遍历数组中的每个项目。我们传递给回调函数的参数(在本例中为item)将代表循环每次迭代中的项目。在 return 内部,我们将创建一个<li>,它将显示的文本将是item,或者说是列表数组当前索引中的文本。

我们得到了什么?

如果我们回到终端并输入yarn startnpm run start,我们就可以localhost:1234在浏览器中看到我们创建的待办事项列表,它显示为无序列表。现在,让我们允许用户将待办事项添加到列表中。

将项目添加到列表

这很简单。首先,我们需要添加代码来渲染一个输入框和一个提交按钮。目前,渲染组件的完整代码应该如下所示:

<div className="content">
  <div className="container">
    <section className="section">
      <ul>
        {this.state.list.map(item => (
          <li key={item}>{item}</li>
        ))}
      </ul>
    </section>
    <hr />
    <section className="section">
      <form className="form" id="addItemForm">
        <input
          type="text"
          className="input"
          id="addInput"
          placeholder="Something that needs ot be done..."
        />
        <button className="button is-info" onClick={this.addItem}>
          Add Item
        </button>
      </form>
    </section>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

添加添加项目的功能

现在我们已经渲染了输入框和按钮,我们需要让它们执行一些操作。否则,用户将无法更改列表。为此,我们需要在addItem()构造函数下方、render 方法之前添加一个函数,该函数调用组件。我们需要在点击按钮时运行该函数。点击按钮后,它会获取输入框中的文本,并判断其是否为空。如果有文本,我们会将其添加到状态数组中,然后更新渲染的页面。以下函数将为输入框添加必要的功能:

addItem(e) {
    // Prevent button click from submitting form
    e.preventDefault();

    // Create variables for our list, the item to add, and our form
    let list = this.state.list;
    const newItem = document.getElementById("addInput");
    const form = document.getElementById("addItemForm");

    // If our input has a value
    if (newItem.value != "") {
      // Add the new item to the end of our list array
      list.push(newItem.value);
      // Then we use that to set the state for list
      this.setState({
        list: list
      });
      // Finally, we need to reset the form
      newItem.classList.remove("is-danger");
      form.reset();
    } else {
      // If the input doesn't have a value, make the border red since it's required
      newItem.classList.add("is-danger");
    }
  }
Enter fullscreen mode Exit fullscreen mode

现在我们已经构建了函数,但它不知道何时运行或如何解释this关键字。我们可以在构造函数中使用以下代码告诉 React 如何处理这个问题:

this.addItem = this.addItem.bind(this);
Enter fullscreen mode Exit fullscreen mode

我们可以为按钮添加一个 onClick 触发器,因此我们的按钮应该如下所示:

<button className="button is-info" onClick={this.addItem}>
  Add Item
</button>
Enter fullscreen mode Exit fullscreen mode

我们可以在浏览器中使用yarn startnpm run start并转到 来测试我们的应用程序localhost:1234。现在我们的应用可以向列表中添加项目了!太酷了!

添加删除按钮

添加删除按钮

好的,现在用户可以添加物品了,但如果添加完后无法删除,那还有什么用呢?他们会不断地添加物品,直到熵值达到顶峰,焦虑程度达到顶峰,最终送他们入土。不如我们加个删除按钮,救救几个人,好吗?

和之前一样,我们将添加一个函数来处理这个问题。下面的代码将允许用户在完成操作后删除列表项:

removeItem(item) {
    // Put our list into an array
    const list = this.state.list.slice();
    // Check to see if item passed in matches item in array
    list.some((el, i) => {
      if (el === item) {
        // If item matches, remove it from array
        list.splice(i, 1);
        return true;
      }
    });
    // Set state to list
    this.setState({
      list: list
    });
  }
Enter fullscreen mode Exit fullscreen mode

添加到构造函数

我们还需要将此函数添加到构造函数中。就像之前一样,我们可以这样做:

this.removeItem = this.removeItem.bind(this);
Enter fullscreen mode Exit fullscreen mode

添加按钮以删除项目

为了方便用户删除项目,我们应该在 中添加一个删除按钮<li>。下面的代码将实现这一点。

...
<ul>
  {this.state.list.map(item => (
    <li key={item}>
      {item} &nbsp;
      <span
        className="delete"
        onClick={() => this.removeItem(item)}
      />
    </li>
  ))}
</ul>
...
Enter fullscreen mode Exit fullscreen mode

现在我们可以在终端中运行yarn startnpm run start来查看更改。现在我们可以点击 x 从列表中删除该项目。成功了吗?

将列表变成组件

呼!目前为止一切都很好。

接下来,我们将把列表转换成一个拥有独立状态和方法的组件。为了简单起见,我将在 app.js 文件中创建该组件,但您也可以在单独的文件中创建并导入它。在 App 组件下方,创建一个名为 List 的类组件,代码如下:

class List extends React.Component {
    render() {
        return (
            <div>
            ...
            </div>
        )
    }
}
Enter fullscreen mode Exit fullscreen mode

我们要渲染的代码只是我们的列表,因此请返回到我们的 App 组件并获取以下代码粘贴到我们的 List 组件的渲染函数中:

<ul>
  {this.state.list.map(item => (
    <li key={item}>
      {item} &nbsp;
      <span
        className="delete"
        onClick={() => this.removeItem(item)}
      />
    </li>
  ))}
</ul>
Enter fullscreen mode Exit fullscreen mode

将 App 组件中的代码替换为对我们的 List 组件的调用,如下所示:

<List items={this.state.list} delete={this.removeItem} />
Enter fullscreen mode Exit fullscreen mode

上面的代码是做什么的?

这里,我们调用 List 组件并传入一些 props。propsitems传入的是我们存储在状态中的列表。propsdelete传入的是removeItem我们创建的用于删除项目的方法。

为了使其正常工作,我们需要稍微修改一下 List 组件。首先,我们需要添加构造函数,以便接收 props。

class List extends React.Component {
    constructor(props) {
        super(props);
    }
    ...
}
Enter fullscreen mode Exit fullscreen mode

npm run start如果我们使用或运行应用程序yarn start,应用程序应该看起来和以前一样。我们仍然可以毫无问题地向列表中添加项目。如果我们点击删除按钮……哦哦……它不起作用。这是为什么呢?

我们在这个组件中没有调用任何方法removeItem,所以点击按钮不会调用任何东西。幸运的是,我们有先见之明,将该方法作为 prop 传递给了组件。要恢复删除功能,我们只需将该按钮的代码改为以下内容:

<span className="delete" onClick={() => this.props.delete(item)} />
Enter fullscreen mode Exit fullscreen mode

经过一些调整,我们现在在一个单独的组件中拥有了一个功能齐全的列表。现在,继续添加搜索功能。

在列表中创建过滤项

添加搜索栏的第一步是创建一个包含已过滤列表的数组。如果输入栏为空,则显示列表中的所有项目。如果搜索栏中有文本,则仅显示包含该文本的项目。

首先,我们将状态添加到 List 组件,并为其添加一个名为 filtered 的数组。以下代码演示了这一点。

class List extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            filtered: []
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

一旦我们有地方放置过滤列表,我们就需要确保数据被放在那里。

温馨提示:这部分内容可能有点抽象,所以请尽量跟上我的思路。如果我解释得不够清楚,或者你遇到困难,请留言,我会尽力帮助你理解。

我们最初的任务列表位于 App 组件中,在本例中是父组件。此状态会被传递到 List 组件(在本例中是子组件),每次任务列表更新时,子组件都会重新渲染。你可能会问,告诉你这些有什么意义?我们需要在filteredList 组件每次重新渲染时将数据传递到状态中。为此,我们将使用一些生命周期方法。

生命周期方法允许我们在组件渲染过程的各个阶段“挂钩”它。在本例中,我们将使用componentDidMountcomponentDidReceivePropscomponentDidMount允许我们在组件首次渲染时将数据放入filtered数组中。另一方面,componentDidReceiveProps将在传入组件的 props 发生变化时触发。

要将这些生命周期方法添加到我们的 List 组件,请在构造函数下方但在渲染函数之前添加以下代码:

componentDidMount() {
  this.setState({
    filtered: this.props.items
  });
}

componentWillReceiveProps(nextProps) {
  this.setState({
    filtered: nextProps.items
  });
}
Enter fullscreen mode Exit fullscreen mode

现在,如果我们.map()将列表使用的函数更改为映射到filtered列表上,而不是items通过 props 传入列表,我们应该在前端看到相同的内容。

呼呼

这有什么大不了的?重要的是,现在我们有了一个可以在不改变原始列表的情况下操作的列表。我们所要做的就是修改filter状态,显示的项目也会反映这一点,但这样做并没有丢失原始列表。

创建搜索栏本身

我觉得,创建搜索栏的一个好起点就是……嗯……搜索栏本身。我们开始创建它吧。在 List 组件的 div 包装器内,添加一个输入框。

<div>
    <input type="text" className="input" placeholder="Search..." />
    <ul>
    ...
    </ul>
</div>
Enter fullscreen mode Exit fullscreen mode

太棒了!现在我们有搜索栏了。要是它真的能用就好了……

使用搜索栏进行搜索

我们有一个好看的搜索栏,但它除了看起来漂亮之外,其实没什么用。也许这已经足够好了,但我认为生活的意义远不止于拥有超级超级好看。我们来加点“大脑”吧。

真的真的好看得可笑

首先,我们将handleChange在生命周期方法之后添加一个名为 的方法。我们将传入e一个代表事件的参数。在该方法内部,我们将创建两个变量,分别保存作为 props 传入的原始任务列表以及传入状态之前的筛选列表。

我们还需要添加一个 if 语句,以便该.filter()函数仅在输入不为空时运行。否则,空的搜索栏将不会显示任何任务。因此,如果搜索栏不为空,我们需要运行该.filter()函数并检查当前项是否包含搜索词。如果包含,则将该项返回到 newList 数组。

handleChange(e) {
        // Variable to hold the original version of the list
    let currentList = [];
        // Variable to hold the filtered list before putting into state
    let newList = [];

        // If the search bar isn't empty
    if (e.target.value !== "") {
            // Assign the original list to currentList
      currentList = this.props.items;

            // Use .filter() to determine which items should be displayed
            // based on the search terms
      newList = currentList.filter(item => {
                // change current item to lowercase
        const lc = item.toLowerCase();
                // change search term to lowercase
        const filter = e.target.value.toLowerCase();
                // check to see if the current list item includes the search term
                // If it does, it will be added to newList. Using lowercase eliminates
                // issues with capitalization in search terms and search content
        return lc.includes(filter);
      });
    } else {
            // If the search bar is empty, set newList to original task list
      newList = this.props.items;
    }
        // Set the filtered state based on what our rules added to newList
    this.setState({
      filtered: newList
    });
  }
Enter fullscreen mode Exit fullscreen mode

使用 时.contains(),它区分大小写。这可能会使用户在任务中搜索时更加困难,因为他们必须确切知道项目使用的大小写。为了解决这个问题,我们可以将函数中的所有内容改为小写,这样我们就知道搜索时所有内容将使用什么大小写。上面的注释也解释了这一点。

将方法添加到输入

快完成了!在使用该handleChange()方法之前,我们需要将关键字绑定this到它。在构造函数内部,状态之后,添加以下代码,将this关键字绑定到该方法。

this.handleChange = this.handleChange.bind(this);
Enter fullscreen mode Exit fullscreen mode

最后,我们可以为输入项添加一个事件处理程序,以便在内容发生更改时调用该方法。这最后一部分才是真正实现搜索功能的关键。将其添加onChange={this.handleChange}到输入元素,使其如下所示:

<input type="text" className="input" onChange={this.handleChange} placeholder="Search..." />
Enter fullscreen mode Exit fullscreen mode

结论

运行该应用程序现在应该允许您创建、删除和搜索任务。这里有很多文本,但实际上并不是那么复杂。

这对你有帮助吗?如果你遇到任何问题,请告诉我,我会更新本教程。我还在下面添加了包含完整代码的 Codepen,方便你试用或比较代码。

本文的原始版本可以在这里找到。

文章来源:https://dev.to/iam_timsmith/lets-build-a-search-bar-in-react-120j
PREV
你应该知道的 Git 技巧
NEXT
用 CSS 编写逻辑 控制结构 逻辑门技术 总结