React 入门:实战案例 Github搜索_axios发送请求

news2025/1/18 4:51:50

文章目录

  • 快速搭建 API 服务器
  • 在 Search 组件中实现 Axios 发送请求
  • 在 App 组件中管理 List 组件的用户列表状态
  • 在 List 组件中更新渲染用户列表数据
  • 优化完善
  • 完整源码

最终效果:
在这里插入图片描述

快速搭建 API 服务器

根据下面步骤来操作,就可以快速搭建一个符合本案例使用 Express 服务器。

  • 在你电脑的某个位置创建一个node-server的目录;

  • 通过命令行工具进入到node-server;

  • node-server目录下执行 npm i express命令安装 Express;

  • node-server目录下创建app.js文件,并键入以下内容:

    // file: node-server/app.js
    
    // 导入 Express
    const express = require("express");
    const axios = require("axios");
    
    // 创建 web 服务器
    const app = express();
    
    // 全局中间件
    app.use((req, res, next) => {
      // console.log("请求来自于:", req.get("Host"));
      // console.log("请求地址:", req.url);
      next();
    });
    
    app.get("/", (req, res) => {
      res.send("hello, express");
    });
    
    app.get("/search/users2", (req, res) => {
      const users = [
        {
          id: "001",
          login: "tom",
          avatar_url: "http://api.btstu.cn/sjtx/api.php?lx=a1&format=images",
          html_url: "",
        },
        {
          id: "002",
          login: "jerry",
          avatar_url: "http://api.btstu.cn/sjtx/api.php?lx=b1&format=images",
          html_url: "",
        },
        {
          id: "003",
          login: "tony",
          avatar_url: "http://api.btstu.cn/sjtx/api.php?lx=c1&format=images",
          html_url: "",
        },
      ];
      res.send(users);
    });
    
    app.get("/search/users", async (req, res, next) => {
      try {
        const data = await axios.get(
          `https://api.github.com/search/users?q=${req.query.q}`
        );
        res.send(data.data);
      } catch (err) {
        next(err);
      }
    });
    
    // 设置端口,监听启动服务器的回调
    app.listen(5000, () => {
      console.log("服务器启动成功:http://localhost:5000");
      console.log("请求github真实数据请访问:http://localhost:5000/search/users");
      console.log("请求本地模拟数据请访问:http://localhost:5000/search/users2");
    });
    
  • 打开 node-server目录下的 package.json 文件,添加如下内容:

    "scripts": {
      "start": "node app.js"
    }
    
  • 通过npm start启动服务器,启动成功控制台输入如下:

    PS E:\node-server> npm start
    
    > start
    > node app.js
    
    服务器启动成功:http://localhost:5000
    请求github真实数据请访问:http://localhost:5000/search/users
    请求本地模拟数据请访问:http://localhost:5000/search/users2
    
  • 启动成功后,在浏览器访问接口,看是否可正常返回数据。

在 Search 组件中实现 Axios 发送请求

  • 在 Search 组建中引入 axios:

    // file: src/components/Search/index.jsx
    
    import axios from "axios";
    
  • 给 input 添加 ref 属性,用来在点击搜索按钮的回调中获取输入的值,也就是查询关键词。

    // file: src/components/Search/index.jsx
    
    <input
      ref={(c) => (this.keyWordElement = c)}
      type="text"
      placeholder="输入关键词点击搜索"
    />
    
  • 定义点击搜索按钮的事件回调:

    // file: src/components/Search/index.jsx
    
    search = () => {
      // 获取用户的输入
      const {
        keyWordElement: { value: keyWord },
      } = this; // 此处运用了连续解构赋值并重命名的写法
      // 发送网络请求
      axios.get(`/search/users?q=${keyWord}`).then(
        (res) => {
          // 此处调用App组件通过props传入的saveUsers方法来更新用户状态,本文下面部分内容有实现
          this.props.saveUsers(res.data.items);
        },
        (err) => {
          console.log("失败了", err);
        }
      );
    };
    

    注意:

    1. 需要配置跨域代理,此处我通过 package.json 配置的,增加以下代码即可:
      "proxy": "http://localhost:5000"
      当然你也可以使用增加 setupProxy.js 文件的方式。
    2. 请求地址 http://localhost:3000/search/users?q=${keyWord} 可以简写为 /search/users?q=${keyWord}
  • 给搜索按钮绑定 click 事件:

    // file: src/components/Search/index.jsx
    
    <button onClick={this.search}>搜索</button>
    

在 App 组件中管理 List 组件的用户列表状态

  • 在 App.js 中对用户列表数据进行初始化,并提供更新该状态的方法,代码如下:

    // file: src/App.js
    
    // 初始化状态
    state = { users: [] };
    
    // 保存更新用户数据状态
    saveUsers = (users) => {
      this.setState({ users });
    };
    
  • 在 App.js 中通过 Search 组件的 props 把 saveUsers 方法传递给 Search 组件,代码如下:

    // file: src/App.js
    
    <Search saveUsers={this.saveUsers} />
    
  • 在 App.js 中通过 List 组件的 props 把 users 数据传递给 List 组件,这样 List 组件就动态渲染数据了,代码如下:

    // file: src/App.js
    
    <List users={users} />
    

在 List 组件中更新渲染用户列表数据

  • 在 List 组件中通过 props 接收到 users 数据,并渲染到界面,代码如下:

    // file: src/components/List/index.jsx
    
    render() {
      const { users } = this.props;
      return (
        <div className="row">
          {users.map((userObj) => {
            return (
              <div key={userObj.id} className="card">
                <a href={userObj.html_url} target="_blank" rel="noreferrer">
                  <img
                    src={userObj.avatar_url}
                    style={{ width: "100px" }}
                    alt="avatar"
                  />
                </a>
                <p className="card-text">{userObj.login}</p>
              </div>
            );
          })}
        </div>
      );
    }
    

    至此,在输入框输入关键字,点击搜索时,用户列表就会显示搜索结果(请求可能会比较慢,后面优化)。

优化完善

上文已实现功能交互,但是体验比较差。体现在以下几点:

  • 首次进入页面时,List 组件区域一片空白,体验不好;
  • 点击搜索后,请求比较慢比较耗时的情况下,List 组件区域要么空白要么还显示搜索前的数据,也就是在结果返回的这段时间里显示的内容体验不好;
  • 还有请求异常或报错的情况未处理。

下面针对以上三点统一进行优化:

  • 首先,在 App.js 中新增定义了 3 个状态,并把之前单独更新 users 的方法重构为一个可以批量更改状态的方法 updateAppState,具体说明如下代码所示:

    // file: src/App.js
    state = {
      users: [], // users 初始值为数组
      isFirst: true, // 是否为第一次打开页面
      isLoading: false, // 是否处于加载中
      err: "", // 存储请求相关的错误信息
    };
    
    // 更新App的state
    updateAppState = (stateObj) => {
      this.setState(stateObj);
    };
    
  • 然后,在 Search 组件中的代码逻辑中来控制 isFirst、isLoading、err 的状态:

    • isFirst 控制逻辑:只要点击一次搜索按钮,就要把 isFirst 设置为 false,直到重新打开页面。
    • isLoading 控制逻辑:axios 发送请求前把 isLoading 设置为 true,请求返回数据(不论成功还是失败)时,设置为 false。
    • err 控制逻辑:当请求失败时来存储错误信息。(注意:每次请求前要清空 err。)

    主要是将 Search 组件中 search 方法代码重构如下:

    // file: src/components/Search/index.jsx
    
    search = () => {
      const {
        keyWordElement: { value: keyWord },
      } = this;
      // 1、发送请求前通知App更新状态
      this.props.updateAppState({ isFirst: false, isLoading: true, err: "" });
      // 发送网络请求
      axios.get(`/search/users?q=${keyWord}`).then(
        (res) => {
          // 2、发送请求成功后通知App更新状态
          this.props.updateAppState({ isLoading: false, users: res.data.items });
        },
        (err) => {
          // 3、发送请求失败后通知App更新状态
          this.props.updateAppState({ isLoading: false, err: err.message });
        }
      );
    };
    
  • 最后,在 List 组件中通过上面新增的 3 个状态,来控制在不同交互场景下的页面显示内容:

    • 首次打开页面(即 isFirst 为 true)时,List 组件区域显示文案“欢迎使用,请输入关键字,随后点击搜索”。
    • 如果加载中(即 isLoading 为 true)时,List 组件区域显示为“Loading…”。
    • 如果有错误信息(即 err 不为空)时,则显示错误信息
    • 否则,正常显示用户数据。
    // file: src/components/List/index.jsx
    
    render() {
      const { users, isFirst, isLoading, err } = this.props;
      return (
        <div className="row">
          {isFirst ? (
            <h4>欢迎使用,请输入关键字,随后点击搜索</h4>
          ) : isLoading ? (
            <h4>Loading......</h4>
          ) : err ? (
            <h4 style={{ color: "red" }}>{err}</h4>
          ) : (
            users.map((userObj) => {
              return (
                <div key={userObj.id} className="card">
                  <a href={userObj.html_url} target="_blank" rel="noreferrer">
                    <img
                      src={userObj.avatar_url}
                      style={{ width: "100px" }}
                      alt="avatar"
                    />
                  </a>
                  <p className="card-text">{userObj.login}</p>
                </div>
              );
            })
          )}
        </div>
      );
    }
    

完整源码

  • App.js

    // file: src/App.js
    
    import React, { Component } from "react";
    import Search from "./components/Search";
    import List from "./components/List";
    
    export default class App extends Component {
      // 初始化状态
      state = {
        users: [], // users 初始值为数组
        isFirst: true, // 是否为第一次打开页面
        isLoading: false, // 是否处于加载中
        err: "", // 存储请求相关的错误信息
      };
    
      // 更新App的state
      updateAppState = (stateObj) => {
        this.setState(stateObj);
      };
    
      render() {
        return (
          <div className="container">
            <Search updateAppState={this.updateAppState} />
            <List {...this.state} />
          </div>
        );
      }
    }
    
  • Search 组件

    // file: src/component/Search.jsx
    
    import React, { Component } from "react";
    import axios from "axios";
    
    export default class Search extends Component {
      search = () => {
        // 获取用户的输入
        const {
          keyWordElement: { value: keyWord },
        } = this; // 此处运用了连续解构赋值并重命名的写法
        // 发送请求前通知App更新状态
        this.props.updateAppState({ isFirst: false, isLoading: true, err: "" });
        // 发送网络请求
        axios.get(`/search/users?q=${keyWord}`).then(
          (res) => {
            // 发送请求成功后通知App更新状态
            this.props.updateAppState({
              isLoading: false,
              users: res.data.items,
            });
          },
          (err) => {
            // 发送请求失败后通知App更新状态
            this.props.updateAppState({ isLoading: false, err: err.message });
          }
        );
      };
    
      render() {
        return (
          <section className="jumbotron">
            <h3 className="jumbotron-heading">搜索 Github 用户</h3>
            <div>
              <input
                ref={(c) => (this.keyWordElement = c)}
                type="text"
                placeholder="输入关键词点击搜索"
              />
              &nbsp;
              <button onClick={this.search}>搜索</button>
            </div>
          </section>
        );
      }
    }
    
  • List 组件

    // file: src/component/List.jsx
    
    import React, { Component } from "react";
    import "./index.css";
    
    export default class List extends Component {
      render() {
        const { users, isFirst, isLoading, err } = this.props;
        return (
          <div className="row">
            {isFirst ? (
              <h4>欢迎使用,请输入关键字,随后点击搜索</h4>
            ) : isLoading ? (
              <h4>Loading......</h4>
            ) : err ? (
              <h4 style={{ color: "red" }}>{err}</h4>
            ) : (
              users.map((userObj) => {
                return (
                  <div key={userObj.id} className="card">
                    <a href={userObj.html_url} target="_blank" rel="noreferrer">
                      <img
                        src={userObj.avatar_url}
                        style={{ width: "100px" }}
                        alt="avatar"
                      />
                    </a>
                    <p className="card-text">{userObj.login}</p>
                  </div>
                );
              })
            )}
          </div>
        );
      }
    }
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/117021.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

明年跨境电商外贸的新增量在哪里?来自专家的2个判断

明年跨境电商外贸的新增量在哪里&#xff1f;来自专家的2个判断2022年&#xff0c;外贸大环境不容易&#xff0c;外贸人也不容易。自2021年9月以来&#xff0c;海运费飙涨&#xff0c;库容一降再降。大批的货品滞留库存&#xff0c;部分卖家只好硬着头皮扛下来了高额的仓储费&a…

最佳实践 | 帮助您的游戏在斋月期间大放异彩

作者 / Google Play 游戏业务发展经理 Nimrod Levy世界各地的开发者都发现&#xff0c;在斋月期间&#xff0c;许多庆祝这个神圣月份的国家/地区的用户都会比平时更活跃。这是一个吸引穆斯林玩家的宝贵机会。斋月是伊斯兰历的第 9 个月。世界各地的穆斯林都会在这个月进行斋戒、…

RV1126笔记二十二:pt->onnx->rknn模型转换

若该文为原创文章,转载请注明原文出处。 一、介绍 实现的目标是,把RK提供的yolov5s.pt转成onnx,在把onnx转成rknn,部署到RV1126上面。 这里不训练模型,所以只要搭建好环境后,就可以直接运行测试。 这里只是提供一种转换的方法,有其他的方式,可以自行测试。 由于不…

立根铸魂 崛起数智时代 操作系统产业峰会2022即将启幕!

如今&#xff0c;数字经济成为全球经济增长的主引擎。基础软件是数字经济发展的基础&#xff0c;是制造强国、网络强国、数字中国建设的关键支撑。而基础软件中的操作系统&#xff0c;作为数字基础设施的底座&#xff0c;已经成为推动产业数字化、智能化发展的核心力量。 2022…

Codeforces Round #840 (Div. 2)

A. Absolute Maximization 题目链接&#xff1a;Problem - A - Codeforces 样例输入&#xff1a; 4 3 1 0 1 4 5 5 5 5 5 1 2 3 4 5 7 20 85 100 41 76 49 36样例输入&#xff1a; 1 0 7 125题意&#xff1a;给定一个长度为n的数组a[]&#xff0c;我们可以对这个数组中的数进…

VueJs中setup的使用(上)

前言在写组合式API代码时,首先接触到的是setup这个函数,在一些项目代码里,你会看到有的直接在script标签上添加setup标识,有的在选项式API方式里,以setup()函数,配置选项的方式出现在单文件组件里什么时候用setup()函数方式,什么时候不用,对于有些新手同学,有些困惑,以及它的一…

聚观早报 | 特斯拉上海工厂被曝停产;富士相机X-Pro 3已停产

今日要闻&#xff1a;特斯拉上海工厂被曝停产&#xff1b;富士相机X-Pro 3已停产&#xff1b;字节复活红果小说App&#xff1b;网易云音乐首份乐评报告发布&#xff1b;辛巴年货节单场带货超1400万单特斯拉上海工厂被曝停产 12 月 26 日消息&#xff0c;根据一份内部通知和两位…

十八、Docker可视化管理工具Portainer

1、概述 Portainer分两个版本 开源版本&#xff1a;Portainer Community Edition (CE) 和商业版本&#xff1a;Portainer 商业版 (BE)。 CE 拥有超过 50 万的普通用户&#xff0c;是一个功能强大的开源工具集&#xff0c;可让您轻松地在 Docker、Docker Swarm、Kubernetes 和…

SpingBoot常见注解区分

1、Mapper注解&#xff1a; 作用&#xff1a;在接口类上添加了Mapper&#xff0c;在编译之后会生成相应的接口实现类 添加位置&#xff1a;接口类上面 Mapper public interface UserMapper{/*** param username 用户名* param password 密码* param memberLevelId 会员级别* p…

【Pygame实战】俄罗斯方块 | 太好玩了~停不下来,这种版本(Turtle彩版)你肯定没玩过……(经典怀旧:无人不知的俄罗斯方块)

导语 警报警报&#xff01;听说CSDN游戏专区火了火了~竟然是因为各种形状的方块。 对&#xff01;各种游戏都快烂大街了&#xff0c;俄罗斯方块咋滴就不能火一把了&#xff1f; Python版俄罗斯方块 等你来战&#xff01; 所有文章完整的素材源码都在&#x1f447;&#x1f447;…

分库分表必知

概述 为啥要进行分库分表&#xff1f; 单表数据量太大&#xff0c;比如超过5000w行&#xff0c;查询时扫描的行太多&#xff0c;SQL效率低&#xff0c;CPU出现瓶颈 数据的切分就是通过某种特定的条件&#xff0c;将存放在同一个数据库或同一个表的数据分散存放到多个数据库&a…

干货 | 数字经济创新创业——网络安全

下文整理自清华大学大数据能力提升项目能力提升模块课程“Innovation & Entrepreneurship for Digital Economy”&#xff08;数字经济创新创业课程)的精彩内容。主讲嘉宾&#xff1a;Kris Singh: CEO at SRII, Palo Alto, CaliforniaVisiting Professor of Tsinghua Unive…

在 ArcGIS 中使用函数块给字段赋随机值 (指定范围内随机编号)

在 ArcMap 或 ArcGIS Pro 中通过使用字段计算器,给字段赋随机值。 通过字段计算器内置的 VB、Python 方法可以构建函数块表达式实现各种各样的赋值操作,下面我们来看看通过使用内置的 Python 函数块来实现随机赋值。 (也可以制作成工具箱哦,更加方便) ArcMap 生成随机值…

智能开关继电器-选型篇2

继电器在智能开关中承担着开通、关断的功能&#xff0c;是开关产品最根本的一项功能。这样一个关键的器件我们将分为两个篇章进行撰写&#xff1a;选型篇1、选型篇2、评估篇。其中选型篇1简述继电器的定义、分类&#xff0c;可参考《智能开关继电器-选型篇1》。选型篇2会在基于…

【TypeScript】类型声明文件的讲解与使用

目录 简介 文件类型 类型声明文件使用 简介 我们发现今天所有的JS应用都会引入许多第三方库来完成任务需求。这些第三方库无论是否是TS编写的最终都会编译成JS代码给开发者使用。我们知道TS提供了类型才有了代码提示和类型保护机制&#xff0c;但我们引入的第三方库都会有相…

搞懂 Spark 系列之 Spark Shuffle 的前世今生

注&#xff1a;本文已首发于PowerData公众号&#xff01; 1 Spark Shuffle 是什么&#xff1f; Shuffle 中文意思是“洗牌&#xff0c;混洗”&#xff0c;而在 Hadoop 的 MapReduce 框架中&#xff0c;Shuffle 是 Map 和 Reduce 中间必不可少的连接桥梁。数据在从Map 阶段结束…

优化器核心技术—Join Reorder

Join Reorder 的简介 Join Reorder 是开务数据库 SQL 优化器中的核心优化算法&#xff0c;开务数据库优化器包括 RBO 和 CBO 两部分&#xff0c;负责计划优化&#xff0c;提升 SQL 执行性能。Join Reorder 能够保证在复杂查询执行的场景下&#xff0c;枚举合法的执行路径&…

分布式系统稳定性建设指南

来源&#xff1a; 中国信息通信研究院 系统稳定性能建设是一个系统化工程&#xff0c;需要硬件软件&#xff0c;需要从企业工程建设的全环节进行设计和实施&#xff0c;充分利用以混沌工程、全链路压测为代表的分布式稳定性保障技术&#xff0c;建设保障能力&#xff0c;改造运…

域名系统 DNS(计算机网络-应用层)

目录 互联网的域名结构 顶级域名 TLD(Top Level Domain) 域名服务器 域名系统 DNS 域名解析的过程 域名服务器的四种类型 本地域名服务器 DNS 协议 DNS缓存 DNS提供的其它服务 互联网的域名结构 域名系统 DNS (Domain Name System)&#xff0c;实现主机名&#xff08;域…

(三)HTTPTomcatServlet

一、HTTP HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff0c;规定了浏览器和服务器之间数据传输的规则。 HTTP协议特点&#xff1a; &#xff08;1&#xff09;基于TCP协议&#xff1a;面向连接&#xff0c;安全 &#xff08;2&#xff09;基于请求-响应模型的…