使用Axios在React中创建实时搜索功能
Axios 是一个强大的 HTTP 客户端,允许在 JavaScript 应用程序中轻松实现 Ajax 请求。 我们在这里 介绍了将 Axios 与 React 一起使用的基础知识,因此如果 Axios 或 Axios + React 对您来说是全新的,您可以先阅读它。
在本教程中,我们将借助 Axios 在 React 应用程序中构建实时搜索功能。 我们的应用程序将允许我们使用来自 themoviedb.org 的 API 进行简单的电影搜索。
本教程分为 3 个部分:
- 第 1 部分:如何使用 Axios 在 React 中进行实时搜索
- 第 2 部分:防止不必要的请求
- 第 3 部分:缓存 HTTP 请求和响应
初始化应用程序
本教程假设您有一些使用 React 的经验,因此我们将跳过初始化步骤以节省我们宝贵的时间。 您可以使用您喜欢的任何样板,在本教程中,我们将简单地使用 Create React App 来初始化应用程序。
初始化应用程序后,让我们添加 axios
到它:
$ yarn add axios or npm i axios
接下来,将以下代码复制到您的 App
组件中:
import React, { Component } from 'react'; import axios from 'axios'; import Movies from './Movies'; class App extends Component { state = { movies: null, loading: false, value: '' }; search = async val => { this.setState({ loading: true }); const res = await axios( `https://api.themoviedb.org/3/search/movie?query=${val}&api_key=dbc0a6d62448554c27b6167ef7dabb1b` ); const movies = await res.data.results; this.setState({ movies, loading: false }); }; onChangeHandler = async e => { this.search(e.target.value); this.setState({ value: e.target.value }); }; get renderMovies() { let movies = <h1>There's no movies</h1>; if (this.state.movies) { movies = <Movies list={this.state.movies} />; } return movies; } render() { return ( <div> <input value={this.state.value} onChange={e => this.onChangeHandler(e)} placeholder="Type something to search" /> {this.renderMovies} </div> ); } } export default App;
注意:Movies
只是展示/哑组件,只是渲染我们给它的数据。 它不会触及我们的数据。
输入组件
因此,我们有一个受控的 input
元素,当我们输入内容时它会调用 onChangeHandler
方法。 onChangeHandler
更改 state
中的 value 属性并调用 search
方法,将输入值作为参数提供给它。
搜索
从上面获取以下代码:
search = async val => { this.setState({ loading: true }); const res = await axios( `https://api.themoviedb.org/3/search/movie?query=${val}&api_key=dbc0a6d62448554c27b6167ef7dabb1b` ); const movies = await res.data.results; this.setState({ movies, loading: false }); };
在 search
方法中,我们向 API 发出 GET
请求以获取我们想要的电影。 一旦我们得到结果,我们通过 setState
更新组件的 state
。 当我们通过 setState
更改状态时,组件会重新渲染更改后的状态。
就那么简单!
防止不必要的请求
您可能会注意到 每次更新输入 时都会发送请求。 这可能导致请求过载,尤其是当我们收到大量响应时。
要查看此问题的实际效果,请在浏览器的 DevTools 中打开网络选项卡。 清除网络选项卡。 在输入中键入一些电影的名称。
如您所见,每次击键时我们都会下载所有数据。 为了解决这个问题,让我们在 src
目录中创建一个 utils.js
文件:
$ cd src $ touch utils.js
将以下代码复制到 utils.js
中:
import axios from 'axios'; const makeRequestCreator = () => { let token; return (query) => { // Check if we made a request if(token){ // Cancel the previous request before making a new request token.cancel() } // Create a new CancelToken token = axios.CancelToken.source() try{ const res = await axios(query, {cancelToken: cancel.token}) const result = data.data return result; } catch(error) { if(axios.isCancel(error)) { // Handle if request was cancelled console.log('Request canceled', error.message); } else { // Handle usual errors console.log('Something went wrong: ', error.message) } } } } export const search = makeRequestCreator()
更改 App
组件以使用我们的新实用函数:
// ... import { search } from './utils' class App extends Component { // ... search = async val => { this.setState({ loading: true }); // const res = await axios( const res = await search( `https://api.themoviedb.org/3/search/movie?query=${val}&api_key=dbc0a6d62448554c27b6167ef7dabb1b` ); const movies = res; this.setState({ movies, loading: false }); }; // ...
现在那里发生了什么?
Axios
有所谓的 取消令牌 允许我们取消请求。
在 makeRequestCreator
中,我们创建了一个名为 token
的变量。 然后通过请求,如果 token
变量存在,我们调用它的 cancel
方法来取消之前的请求。 然后我们为 token
分配一个新的 CancelToken
。 之后,我们使用给定的查询发出请求并返回结果。
如果出现问题,我们会在 catch
块中捕获错误,我们可以检查并处理请求是否被取消。
现在让我们看看网络选项卡中发生了什么:
如您所见,我们只下载了一个回复。 现在我们的用户只为他们使用的东西付费。
缓存 HTTP 请求和响应
如果我们在输入中多次输入相同的文本,那么我们每次都会发出一个新的请求。
让我们解决这个问题。 我们将稍微改变 utils.js
中的效用函数:
const resources = {}; const makeRequestCreator = () => { let cancel; return async query => { if (cancel) { // Cancel the previous request before making a new request cancel.cancel(); } // Create a new CancelToken cancel = axios.CancelToken.source(); try { if (resources[query]) { // Return result if it exists return resources[query]; } const res = await axios(query, { cancelToken: cancel.token }); const result = res.data.results; // Store response resources[query] = result; return result; } catch (error) { if (axios.isCancel(error)) { // Handle if request was cancelled console.log('Request canceled', error.message); } else { // Handle usual errors console.log('Something went wrong: ', error.message); } } }; }; export const search = makeRequestCreator()
在这里,我们创建了一个 resources
常量来保存我们下载的响应。 当我们做一个新的请求时,我们首先检查我们的 resources
对象是否有这个查询的结果。 如果是这样,我们只返回该结果。 如果没有合适的结果,我们会发出一个新请求并将结果存储在 resources
中。 够简单!
让我们用几句话来总结一下。 每次我们在 input
中键入内容时:
- 如果有的话,我们会取消之前的请求。
- 如果我们已经有我们键入的内容的先前结果,我们只需返回它而不发出新请求。
- 如果我们没有那个结果,我们会制作一个新的并存储它。
如果你有兴趣,你可以在 this repo 中找到这个应用程序的 Redux 版本
结论
恭喜🎉🎉🎉! 我们构建了一个实时搜索功能,它不会下载不必要的响应以及缓存响应。 我希望你已经了解了如何在 Axios 的帮助下在 React 中构建 高效 实时搜索功能。
现在,我们的用户花费尽可能少的流量数据。 如果您喜欢本教程,请分享出去! 😄
您可以在 this CodeSandbox 中找到这篇文章的最终结果和源代码。