如何在 React 中编写带有建议的搜索组件

2025-06-07

如何在 React 中编写带有建议的搜索组件

Github Repo
此示例使用需要转译的语法。完整的 Babel 配置请参见 repo。

提供搜索建议是提升用户体验的好方法。它不仅可以节省时间,还能引导那些不确定自己在寻找什么的用户。

确定了“为什么”之后,我们就可以开始实施了。但是,该如何在 JavaScript 中实现建议呢?

与大多数解决问题的练习一样,一个好的开始是提出正确的问题:

  • 有没有一个库可以解决我的问题?我应该用它吗? 在谷歌上快速搜索一下,会得到类似 autocomplete.js的选项,但自己写一个也能带来一些有价值的见解。

  • 我们要操作哪些 HTML 元素? 看起来我们可以使用 <form><input/><ul>

我们决定自己写。

我们需要:

  • 信息源。我们需要一组值来与用户输入的内容进行比较(我们将使用 API 响应作为信息源,但您也可以使用本地值数组)。

  • 一个 HTTP 客户端。允许我们向特定端点发出请求以获取所需的数据。我选择axios是因为它比Fetch API提供了一些额外的功能,例如自动解析接收到的数据。

  • 一个智能/容器组件,引用受控输入进行 API 调用。

  • 用于显示结果的展示性(无状态功能性)组件。

让我们从容器开始,搜索:

import React, { Component } from 'react'

class Search extends Component {
 state = {
   query: '',
 }

 handleInputChange = () => {
   this.setState({
     query: this.search.value
   })
 }

 render() {
   return (
     <form>
       <input
         placeholder="Search for..."
         ref={input => this.search = input}
         onChange={this.handleInputChange}
       />
       <p>{this.state.query}</p>
     </form>
   )
 }
}

export default Search

Enter fullscreen mode Exit fullscreen mode

您会注意到,当您在输入框中输入内容时,它Search会重新渲染,并且输入的值会显示在下方。借助refs,我们可以选择输入元素并执行一些有用的操作,例如获取其值或调用 DOM 事件focus(例如 this.search.focus())。

接下来,让我们连接一个 API。这里我们将使用MusicGraph ,一个音乐信息数据库。点击此处获取 API 密钥

我们将使用 axios 来创建一个getInfo方法(检查你的 API 文档以了解如何构造你的请求 URL):

  getInfo = () => {
    axios.get(`${API_URL}?api_key=${API_KEY}&prefix=${this.state.query}&limit=7`)
      .then(({ data }) => {
        this.setState({
          results: data.data
        })
      })
  }

Enter fullscreen mode Exit fullscreen mode

Axios.get返回一个 Promise,这意味着它在等待 API 响应时不会阻止应用程序其他部分的执行。这里,我们向 MovieGraph API 的艺术家端点发出请求,并使用 refs 的魔力来填充前缀查询参数。(API_URL 和 API_KEY 在类定义上方定义,请参阅下图。)

我们再调整一下handleInputChange方法。我们不需要在每个 onChange 事件或输入被清除时都调用 API。

目前为止的完整组件:

import React, { Component } from 'react'
import axios from 'axios'

const { API_KEY } = process.env
const API_URL = 'http://api.musicgraph.com/api/v2/artist/suggest'

class Search extends Component {
  state = {
    query: '',
    results: []
  }

  getInfo = () => {
    axios.get(`${API_URL}?api_key=${API_KEY}&prefix=${this.state.query}&limit=7`)
      .then(({ data }) => {
        this.setState({
          results: data.data // MusicGraph returns an object named data, 
                             // as does axios. So... data.data                             
        })
      })
  }

  handleInputChange = () => {
    this.setState({
      query: this.search.value
    }, () => {
      if (this.state.query && this.state.query.length > 1) {
        if (this.state.query.length % 2 === 0) {
          this.getInfo()
        }
      } 
    })
  }

  render() {
    return (
      <form>
        <input
          placeholder="Search for..."
          ref={input => this.search = input}
          onChange={this.handleInputChange}
        />
        <p>{this.state.query}</p>
      </form>
    )
  }
}

export default Search

Enter fullscreen mode Exit fullscreen mode

如果您的浏览器中安装了 React Dev Tools,您可以在 API 调用完成时观察搜索状态的变化:
React 开发工具

冲刺阶段。现在将结果渲染到 DOM。

正如设置中提到的,让我们创建我们的演示组件Suggestions

import React from 'react'

const Suggestions = (props) => {
  const options = props.results.map(r => (
    <li key={r.id}>
      {r.name}
    </li>
  ))
  return <ul>{options}</ul>
}

export default Suggestions
Enter fullscreen mode Exit fullscreen mode

我们已经设置了建议以期待一个名为的道具results

让我们呈现我们的建议组件:

import React, { Component } from 'react'
import axios from 'axios'
import Suggestions from 'components/Suggestions'

const { API_KEY } = process.env
const API_URL = 'http://api.musicgraph.com/api/v2/artist/suggest'

class Search extends Component {
  state = {
    query: '',
    results: []
  }

  getInfo = () => {
    axios.get(`${API_URL}?api_key=${API_KEY}&prefix=${this.state.query}&limit=7`)
      .then(({ data }) => {
        this.setState({
          results: data.data
        })
      })
  }

  handleInputChange = () => {
    this.setState({
      query: this.search.value
    }, () => {
      if (this.state.query && this.state.query.length > 1) {
        if (this.state.query.length % 2 === 0) {
          this.getInfo()
        }
      } else if (!this.state.query) {
      }
    })
  }

  render() {
    return (
      <form>
        <input
          placeholder="Search for..."
          ref={input => this.search = input}
          onChange={this.handleInputChange}
        />
        <Suggestions results={this.state.results} />
      </form>
    )
  }
}

export default Search

Enter fullscreen mode Exit fullscreen mode

尝试一下:

有效的自动完成功能

有用!

路由设置完成后,我们可以将每个结果包装到anchor/react-routerLink组件中。不过这是另一篇文章的主题了。在此之前,我希望这篇文章能对大家有所帮助!

文章来源:https://dev.to/saaage/how-to-write-a-search-component-with-suggestions-in-react-d20
PREV
女性开发者的世界👩‍💻
NEXT
🏆 在你的 readme 中添加动态生成的 GitHub 奖杯快速入门关于排名关于显示详细信息