博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Axios遇到React如何优雅的实现实时搜索
阅读量:6623 次
发布时间:2019-06-25

本文共 5846 字,大约阅读时间需要 19 分钟。

「框架篇」Axios遇到React如何优雅的实现实时搜索

本文所使用的
React 为最新版16.83,其中用到了高阶组件
react.memo(),处理异步请求的 async/await,基于Promise 的 HTTP 库
axios 用于数据请求,以及用来取消请求的 axios API
axios.CancelToken.source(),用心看下去你会有所收获。

在文中,我们将使用 React 结合 Axios 在应用中构建实时搜索功能。会对不必要的请求进行处理优化,并且还对HTTP请求数据进行缓存等。

初始化应用程序

本文中,我们使用 react 官方提供的 Create React App 来初始化应用程序,需要 node >= 6.0,npm >= 5.2 。然后运行以下命名:

npx create-react-app axios-reactcd axios-reactnpm start or yarn start

应用程序初始化后,安装 axios:

npm install axios or yarn add axios

接下来,将下面的代码复制到 App.js 组件中,我们先不用管 Movies 组件里是什么。

import React, { Component } from 'react';import axios from 'axios';import Movies from './Movies;class App extends Component {  //state 定义我们所需要的数据  state = {     value: '',    movies: null,    loading: false  }  search = async val => {    this.setState({ loading: true });    const res = await axios(`https://api.themoviedb.org/3/search/moviequery=${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 = 

没有搜索结果

if(this.state.loading) { movies =

LOADING ...

} if(this.state.movies) { movies =
; } return movies; } render() { return (
this.onChangeHandler(e)} placeholder="试着输入一些内容" />
{this.renderMovies}
); } } export default App;

输入框内容改变

从代码中我们看到有一个受控 input 元素,当输入内容时,调用onChangeHandler 方法。onChangeHandler 方法做了两件事情:一是调用 search 方法并将输入的内容传参给 search;二是修改 state 中的 value属性。

onChangeHandler = async e => {    //调用search 方法    this.search(e.target.value);    //更改state    this.setState({      value: e.target.value    }) }

搜索

search 方法中,我们使用 GET 请求,从API获取我们想要的数据。一旦请求发送成功时,我们就会更新组件 state 的 loading 属性为 true,表示正在等待结果。当我们得到返回的结果时,将更新 state movies 属性,并关闭请求状态。我们使用了 async/await 来处理异步请求,这里先不对这个做过多的介绍。

search = async val => {  this.setState({ loading: true });  const res = await axios(    `https://api.themoviedb.org/3/search/moviequery=${val}&api_key=dbc0a6d62448554c27b6167ef7dabb1b`  );    const movies = await res.data.results;    this.setState({ movies, loading: false });};

渲染数据

在这里我们使用名为 renderMovies 的 get 方法通过 props 将获取到的数据传递给 Movies 组件。

get renderMovies() {    let movies = 

没有搜索结果

if(this.state.loading) { movies =

LOADING ...

} if(this.state.movies) { movies =
; } return movies;}

Movies组件

我们在src 目录下创建 Movies.js 文件,并复制下边代码到此文件中。

import React from 'react';const Movie = props => {  let movie = 

暂无数据

; if(props.list.length) { movie = props.list.map((item, index) => { const { title, poster_path, vote_average } = item; const src = poster_path && `url(http://image.tmdb.org/t/p/w185${poster_path})`; return (
{vote_average}

{title}

) }) } return movie;}//16.6版本中更新了一些包装函数//其中 React.memo() 是一个高阶函数//它与 React.PureComponent类似//但是一个纯函数组件而非一个类const Movies = React.memo(Movie);export default Movies;

Movies 组件做的事情很简单,就是将从 props 里接收过来的数据进行解析,并渲染到页面上,这里用到了包装函数 (wrapped functions) Reacta.memo() 用来优化应用性能,这里不对这个函数进行过多的介绍。

就是这么简单?

防止不必要的请求

我们打开浏览中的开发者工具 network 选项,您可能会注意到我们每次更新输入时都会发送请求,并且会有大量的重复请求,这可能导致请求过载,尤其是当我们收到大量响应时。

图片描述
在解决这个问题之前,我们先在 src 目录下创建 utils.js 文件,将以下代码复制进去。

import axios from 'axios';const axiosRequester = () => {  let cancel;  return async url => {    if(cancel) {      //如果token存在,就取消请求      cancel.cancel();    }    //创建一个新的cancelToken    cancel = axios.CancelToken.source();        try {      const res = await axios(url, {         cancelToken: cancel.token      })            const result = res.data.results;      return result;    } catch(error) {      if(axios.isCancel(error)) {        console.log('Request canceled', error.message);      } else {        console.log(error.message);      }    }  }}export const _search = axiosRequester();

修改 App 组件中的代码:

...import { _search } from './utils';class App extends Component {  ...  search = async val => {    this.setState({ loading: true  }          const url = `https://api.themoviedb.org/3/search/movie?query=${val}&api_key=dbc0a6d62448554c27b6167ef7dabb1b`      const res = await _search(url);      const movies = res;    this.setState({ movies, loading: false });  }  ...

我们都做了什么

Axios 提供了所谓的取消令牌(cancel token)功能,允许我们取消请求。

axiosRequester 我们创建一个名为的 cancel 变量。然后发送请求,如果 cancel 变量存在,我们调用其 cancel 方法取消先前的请求。然后我们分配 一个 新的 tokenCancelToken。之后,我们使用给定的查询发出请求并返回结果。

我们使用 try/catch 对问题进行捕获,我们可以检查并处理请求是否被取消。

我们现在看看开发者工具中 network 是什么样子的:

图片描述

我们看到请求都被我们取消掉了,因为这些请求之前已经请求过了。

缓存HTTP请求和数据

如果我们在多次输入中键入相同的文本,我们每次都会发出一次新的请求,这显然不是我们想要的结果。解决这个问题,我们将 utils.js 稍微改变下:

import axios from 'axios';//用来存储已经请求过的数据const resources = {};const axiosRequester = () => {  let cancel;  return async url => {    if(cancel) {      //如果token存在,就取消请求      cancel.cancel();    }    //创建一个新的cancelToken    cancel = axios.CancelToken.source();    try {      //如果请求的数据已经存在,缓存之前请求回来的数据      if(resources[url]) {         return resources[url];      }      const res = await axios.post(url, {         cancelToken: cancel.token      })      const result = res.data.results;      //将url作为key, 记录请求回来的数据      resources[url] = result;       return result;    } catch(error) {      if(axios.isCancel(error)) {        console.log('Request canceled', error.message);      } else {        console.log(error.message);      }    }  }}export const _search = axiosRequester();

这里我们创建了一个 resources 对象用来缓存我们请求的结果。当正在执行新请求时,我们首先检查我们的 resources 对象是否具有此次查询的结果。如果存在,我们只返回该结果。如果不存在,我们会发出新请求并将对应的结果存储到 resources 中。

让我们用几句话总结一下,当我们在input框中输入内容时:

如果有过的话,我们取消之前的请求。

如果我们已经输入了之前的内容,我们只需返回之前的数据,不会发出新请求。

如果是新的请求,我们会将获得的新的数据缓存起来。

如果想要了解更多,请搜索微信公众号webinfoq

转载地址:http://txjpo.baihongyu.com/

你可能感兴趣的文章
第1章关键角色及其职责——明白职责
查看>>
IOS CoreData 多表查询(下)
查看>>
mysql查询常用小语句
查看>>
mysql 数据库安装步骤个人总结
查看>>
webservice测试工具
查看>>
[Oracle]如何获得出现故障时,客户端的详细连接信息
查看>>
BabeLua常见问题
查看>>
python -- ajax数组传递和后台接收
查看>>
Porting .Net RSA xml keys to Java
查看>>
检测 nginx.conf 是否配置正确
查看>>
最长公共子序列|最长公共子串|最长重复子串|最长不重复子串|最长回文子串|最长递增子序列|最大子数组和...
查看>>
测试妹子的呐喊:为什么总是收不到推送?
查看>>
linux NFS
查看>>
Jquery DataTable基本使用
查看>>
New UWP Community Toolkit
查看>>
JDBC连接数据库(二)
查看>>
leetcode 674. Longest Continuous Increasing Subsequence
查看>>
Extensions in UWP Community Toolkit - SurfaceDialTextbox
查看>>
Golang 语言的单元测试和性能测试(也叫 压力测试)
查看>>
springboot数据库连接池使用策略
查看>>