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 = There's no movies; if (this.state.movies) { movies = ; } return movies; } render() { return ( this.onChangeHandler(e)} placeholder="Type something to search" /> {this.renderMovies} ); } } export default App;
注意:Movies
这只是展示/哑组件,仅呈现我们提供的数据。它不会触碰我们的数据。
输入组件
因此,我们有一个受控元素,当我们输入某些内容时,input
它会调用方法。更改中的值属性并调用该方法,将输入的值作为参数传递给它。onChangeHandler
onChangeHandler
state
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
以获取我们想要的电影。一旦我们得到结果,我们就会更新组件的state
via setState
。当我们通过 via 更改状态时setState
,组件会使用更改后的状态重新渲染。
就那么简单!
防止不必要的请求
你可能会注意到,我们每次更新输入时都会发送请求。这可能会导致请求过载,尤其是当我们收到大量响应时。
要查看此问题的实际效果,请在浏览器的 DevTools 中打开网络选项卡。清除网络选项卡。在输入中输入一些电影的名称。
如您所见,每次击键时我们都会下载所有数据。为了解决这个问题,我们utils.js
在目录中创建一个文件src
:
$ 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
:
如果有的话,我们将取消之前的请求。
如果我们已经获得了所输入内容的先前结果,我们就会直接返回它,而无需发出新的请求。
如果我们没有得到那个结果,我们会得出一个新的结果并存储它。
如果你有兴趣,你可以在这个 repo中找到这个应用程序的 Redux 版本
结论
恭喜成功了