使用 Axios 在 React 中创建实时搜索功能

Axios 是一个强大的 HTTP 客户端,允许您在 JavaScript 应用程序中轻松实现 Ajax 请求,我们已经涵盖了使用 Axios 的基本知识,所以您可以首先阅读 Axios 或 Axios + React 对您来说都是新的。

在本教程中,我们将使用Axios构建一个React应用程序内部的实时搜索功能,我们的应用程序将允许我们使用来自 themoviedb.org的API进行简单的电影搜索。

本教程分为3个部分:

初始化 app

本教程假设您有使用 React 的经验,所以我们将跳过初始化步骤来节省我们宝贵的时间. 您可以使用您最喜欢的锅炉板,在本教程中我们将简单地使用 Create React App来初始化应用程序。

一旦应用程序初始化,让我们添加axios:

1$ yarn add axios or npm i axios

接下来,将下面的代码复制到您的应用程序组件:

 1import React, { Component } from 'react';
 2import axios from 'axios';
 3
 4import Movies from './Movies';
 5
 6class App extends Component {
 7  state = {
 8    movies: null,
 9    loading: false,
10    value: ''
11  };
12
13  search = async val => {
14    this.setState({ loading: true });
15    const res = await axios(
16      `https://api.themoviedb.org/3/search/movie?query=${val}&api_key=dbc0a6d62448554c27b6167ef7dabb1b`
17    );
18    const movies = await res.data.results;
19
20    this.setState({ movies, loading: false });
21  };
22
23  onChangeHandler = async e => {
24    this.search(e.target.value);
25    this.setState({ value: e.target.value });
26  };
27
28  get renderMovies() {
29    let movies = <h1>There's no movies</h1>;
30    if (this.state.movies) {
31      movies = <Movies list={this.state.movies} />;
32    }
33
34    return movies;
35  }
36
37  render() {
38    return (
39      <div>
40        <input
41          value={this.state.value}
42          onChange={e => this.onChangeHandler(e)}
43          placeholder="Type something to search"
44        />
45        {this.renderMovies}
46      </div>
47    );
48  }
49}
50
51export default App;

注意:‘电影’只是演示 / 愚蠢的组件,它只是渲染我们给它的数据。

输入组件

因此,我们有一个受控的输入元素,当我们输入时将onChangeHandler方法称为onChangeHandler

搜索

從上面拿下列代碼:

1search = async val => {
2  this.setState({ loading: true });
3  const res = await axios(
4    `https://api.themoviedb.org/3/search/movie?query=${val}&api_key=dbc0a6d62448554c27b6167ef7dabb1b`
5  );
6  const movies = await res.data.results;
7
8  this.setState({ movies, loading: false });
9};

搜索方法中,我们正在向我们的API发出一个GET请求,以获取我们想要的电影。一旦我们得到结果,我们通过setState更新了组件的状态

这么简单!

避免不必要的请求

您可能会注意到,我们每次更新输入时都会发送请求,这可能会导致请求过载,特别是当我们收到大量响应时。

要查看此问题,请在浏览器的 DevTools 中打开网络选项卡,清除网络选项卡,在输入中输入一部电影的名称。

Too many requests, as can be seen from DevTools

正如你所看到的,我们每一次键入时都会下载所有数据. 为了解决这个问题,让我们在src目录中创建一个utils.js文件:

1$ cd src
2$ touch utils.js

将以下代码复制到 utils.js:

 1import axios from 'axios';
 2
 3const makeRequestCreator = () => {
 4  let token;
 5
 6  return (query) => {
 7    // Check if we made a request
 8    if(token){
 9      // Cancel the previous request before making a new request
10      token.cancel()
11    }
12    // Create a new CancelToken
13    token = axios.CancelToken.source()
14    try{
15      const res = await axios(query, {cancelToken: cancel.token})
16      const result = data.data
17      return result;
18    } catch(error) {
19        if(axios.isCancel(error)) {
20          // Handle if request was cancelled
21          console.log('Request canceled', error.message);
22        } else {
23          // Handle usual errors
24          console.log('Something went wrong: ', error.message)
25        }
26    }
27  }
28}
29
30export const search = makeRequestCreator()

也可以更改应用组件以利用我们的新实用功能:

 1// ...
 2import { search } from './utils'
 3
 4class App extends Component {
 5  // ...
 6
 7  search = async val => {
 8    this.setState({ loading: true });
 9    // const res = await axios(
10    const res = await search(
11      `https://api.themoviedb.org/3/search/movie?query=${val}&api_key=dbc0a6d62448554c27b6167ef7dabb1b`
12    );
13    const movies = res;
14
15    this.setState({ movies, loading: false });
16  };
17  // ...

现在在那里发生了什么?

Axios被称为取消令牌(LINK0)使我们能够取消请求。

makeRequestCreator中,我们创建了一个名为token的变量,然后在一个请求中,如果存在token的变量,我们将其称为cancel的方法,以取消以前的请求,然后我们将token分配给一个新的CancelToken

如果有什么不对劲,我们会捕捉到捕获块中的错误,我们可以检查并处理请求是否被取消。

现在让我们看看网络标签中发生了什么:

Screenshot: much better performance!

正如你所看到的,我们只下载了一个答案. 现在 我们的用户只支付他们使用的东西

HTTP 请求和响应

如果我们在输入中多次输入相同的文本,我们每次都会提出新的请求。

我们会改变我们的实用程序函数在utils.js一点点:

 1const resources = {};
 2
 3const makeRequestCreator = () => {
 4  let cancel;
 5
 6  return async query => {
 7    if (cancel) {
 8      // Cancel the previous request before making a new request
 9      cancel.cancel();
10    }
11    // Create a new CancelToken
12    cancel = axios.CancelToken.source();
13    try {
14      if (resources[query]) {
15        // Return result if it exists
16        return resources[query];
17      }
18      const res = await axios(query, { cancelToken: cancel.token });
19
20      const result = res.data.results;
21      // Store response
22      resources[query] = result;
23
24      return result;
25    } catch (error) {
26      if (axios.isCancel(error)) {
27        // Handle if request was cancelled
28        console.log('Request canceled', error.message);
29      } else {
30        // Handle usual errors
31        console.log('Something went wrong: ', error.message);
32      }
33    }
34  };
35};
36
37export const search = makeRequestCreator()

在这里,我们创建了一个资源常数,它保留了我们下载的答案。当我们提出一个新的请求时,我们首先检查我们的资源对象是否有这个请求的结果。

让我们用几句话概括一切。 每当我们在输入中输入某些东西时:

  • 我们取消以前的请求,如果有 *如果我们已经有以前的结果,我们只会返回它而不做一个新的请求 *如果我们没有这个结果,我们会创建一个新的结果,并存储它

如果您感兴趣,您可以在 This repo找到该应用程序的Redux版本。

结论

Congrats 🎉🎉🎉! We've built a live search feature which doesn't download unnecessary responses as well as caches responses. I hope you've learned a thing or two about how to build an efficient live search feature in React with the help of Axios.

现在,我们的用户花费尽可能少的流量数据. 如果你喜欢这个教程,请分享它! 😄

您可以找到本文的最终结果和源代码在 This CodeSandbox中。

Published At
Categories with 技术
Tagged with
comments powered by Disqus