如何在 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
您会注意到,当您在输入框中输入内容时,它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
})
})
}
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
如果您的浏览器中安装了 React Dev Tools,您可以在 API 调用完成时观察搜索状态的变化:
冲刺阶段。现在将结果渲染到 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
我们已经设置了建议以期待一个名为的道具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
尝试一下:
有用!
路由设置完成后,我们可以将每个结果包装到anchor/react-routerLink
组件中。不过这是另一篇文章的主题了。在此之前,我希望这篇文章能对大家有所帮助!