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

游客2024-06-20 05:40:14

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它会调用方法。更改中的值属性并调用该方法,将输入的值作为参数传递给它。onChangeHandleronChangeHandlerstatesearch

取上面这段代码:

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以获取我们想要的电影。一旦我们得到结果,我们就会更新组件的statevia setState。当我们通过 via 更改状态时setState,组件会使用更改后的状态重新渲染。

就那么简单!

防止不必要的请求

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

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


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

如您所见,每次击键时我们都会下载所有数据。为了解决这个问题,我们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,并且我们可以检查和处理请求是否被取消。

让我们看看现在网络选项卡中发生了什么:

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

如您所见,我们仅下载了一个响应。

缓存 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 版本

结论

恭喜成功了