文章目录
- 1 前言
- 2 静态组件
- 2.1 静态页面和样式
- 2.2 静态组件
- 3 axios请求github接口
- 4 优化案例
- 结语
1 前言
学习了脚手架配置axios,我们通过访问github的接口来做个练习。实例效果如下所示:
搜索框输入github用户名关键字,点击搜索,列表展示对应的头像和用户名,点击跳转github主页。
基于我们访问github访问慢或者根本打不开的情况,我们通过nodejs,简单的写了个后端服务,代码1-1如下:
const express = require("express")
const axios = require("axios")
const app = express()
/*
请求地址: http://localhost:3000/search/users?q=aa
后台路由
key: /search/users
value: function () {}
*/
app.get("/search/users", function (req, res) {
const {q} = req.query
axios({
url: 'https://api.github.com/search/users',
params: {q}
}).then(response => {
res.json(response.data)
})
})
app.get("/search/users2", function (req, res) {
res.json({
items: [
{
login: "yyx990803",
html_url: "https://github.com/yyx990803",
avatar_url:
"https://avatars3.githubusercontent.com/u/499550?s=460&u=de41ec9325e8a92e281b96a1514a0fd1cd81ad4a&v=4",
id: 1,
},
{
login: "ruanyf",
html_url: "https://github.com/ruanyf",
avatar_url: "https://avatars2.githubusercontent.com/u/905434?s=460&v=4",
id: 2,
},
{
login: "yyx9908032",
html_url: "https://github.com/yyx990803",
avatar_url:
"https://avatars3.githubusercontent.com/u/499550?s=460&u=de41ec9325e8a92e281b96a1514a0fd1cd81ad4a&v=4",
id: 3,
},
{
login: "ruanyf2",
html_url: "https://github.com/ruanyf",
avatar_url: "https://avatars2.githubusercontent.com/u/905434?s=460&v=4",
id: 4,
},
{
login: "yyx9908033",
html_url: "https://github.com/yyx990803",
avatar_url:
"https://avatars3.githubusercontent.com/u/499550?s=460&u=de41ec9325e8a92e281b96a1514a0fd1cd81ad4a&v=4",
id: 5,
},
{
login: "ruanyf3",
html_url: "https://github.com/ruanyf",
avatar_url: "https://avatars2.githubusercontent.com/u/905434?s=460&v=4",
id: 6,
},
{
login: "yyx9908034",
html_url: "https://github.com/yyx990803",
avatar_url:
"https://avatars3.githubusercontent.com/u/499550?s=460&u=de41ec9325e8a92e281b96a1514a0fd1cd81ad4a&v=4",
id: 7,
},
{
login: "ruanyf4",
html_url: "https://github.com/ruanyf",
avatar_url: "https://avatars2.githubusercontent.com/u/905434?s=460&v=4",
id: 8,
},
{
login: "yyx9908035",
html_url: "https://github.com/yyx990803",
avatar_url:
"https://avatars3.githubusercontent.com/u/499550?s=460&u=de41ec9325e8a92e281b96a1514a0fd1cd81ad4a&v=4",
id: 9,
},
],
});
});
app.listen(5000, "localhost", (err) => {
if (!err){
console.log("服务器启动成功")
console.log("请求github真实数据请访问:http://localhost:5000/search/users")
console.log("请求本地模拟数据请访问:http://localhost:5000/search/users2")
}
else console.log(err);
})
- 如果正常访问github接口
https://api.github.com/search/users
网络延迟高或者打不开,可以切换为我们模拟的接口。
2 静态组件
2.1 静态页面和样式
页面简单的包含搜索组件和列表展示组件,静态html和css代码如下2-1所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="./bootstrap.css">
<link rel="stylesheet" href="./index.css">
</head>
<body>
<div id="app">
<div class="container">
<section class="jumbotron">
<h3 class="jumbotron-heading">Search Github Users</h3>
<div>
<input type="text" placeholder="enter the name you search"/> <button>Search</button>
</div>
</section>
<div class="row">
<div class="card">
<a href="https://github.com/reactjs" target="_blank">
<img src="https://avatars.githubusercontent.com/u/6412038?v=3" style='width: 100px'/>
</a>
<p class="card-text">reactjs</p>
</div>
<div class="card">
<a href="https://github.com/reactjs" target="_blank">
<img src="https://avatars.githubusercontent.com/u/6412038?v=3" style='width: 100px'/>
</a>
<p class="card-text">reactjs</p>
</div>
<div class="card">
<a href="https://github.com/reactjs" target="_blank">
<img src="https://avatars.githubusercontent.com/u/6412038?v=3" style='width: 100px'/>
</a>
<p class="card-text">reactjs</p>
</div>
<div class="card">
<a href="https://github.com/reactjs" target="_blank">
<img src="https://avatars.githubusercontent.com/u/6412038?v=3" style='width: 100px'/>
</a>
<p class="card-text">reactjs</p>
</div>
<div class="card">
<a href="https://github.com/reactjs" target="_blank">
<img src="https://avatars.githubusercontent.com/u/6412038?v=3" style='width: 100px'/>
</a>
<p class="card-text">reactjs</p>
</div>
</div>
</div>
</div>
</body>
</html>
样式使用bootstrap的样式,我们直接放入public\css下面,在主页index.html引入
我们自定义的样式,自定义样式代码如下:
.album {
min-height: 50rem; /* Can be removed; just added for demo purposes */
padding-top: 3rem;
padding-bottom: 3rem;
background-color: #f7f7f7;
}
.card {
float: left;
width: 33.333%;
padding: .75rem;
margin-bottom: 2rem;
border: 1px solid #efefef;
text-align: center;
}
.card > img {
margin-bottom: .75rem;
border-radius: 100px;
}
.card-text {
font-size: 85%;
}
2.2 静态组件
使用脚手架创建项目后,去除不需要的文件,其中public/css 下放置bootstrap.css,在index.html中引入,代码如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="stylesheet" href="./css/bootstrap.css">
<title>React 脚手架</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
src目录下创建2个组件:
- Search组件:对应页面搜索部分;
- List组件:对应列表展示部分。
App.jsx代码2.2-2如下所示:
import React, { Component } from 'react'
import './app.css'
import Search from './component/Search'
import List from './component/List'
export default class App
extends Component {
render() {
// const { githubUsers } = this.state
return (
<div>
<div className="container">
<Search />
<List />
</div>
</div>
)
}
}
Seach组件初始状态代码2.2-3如下所示:
import React, { Component } from 'react'
export default class Search extends Component {
render() {
return (
<section className="jumbotron">
<h3 className="jumbotron-heading">搜索github用户</h3>
<div>
<input type="text" placeholder="输入用户名" />
<button>搜索</button>
</div>
</section>
)
}
}
List组件初始状态代码2.2-4如下所示:
import React, { Component } from 'react'
export default class List extends Component {
render() {
const { isFirst, isLoading, githubUsers, err } = this.props
return (
<div className="row">
<div className="card" >
<a target="_blank">
<img alt='avatar' src="https://avatars.githubusercontent.com/u/6412038?v=3" style={{ width: '100px' }} />
</a>
<p className="card-text">xxx</p>
</div>
<div className="card" >
<a target="_blank">
<img alt='avatar' src="https://avatars.githubusercontent.com/u/6412038?v=3" style={{ width: '100px' }} />
</a>
<p className="card-text">xxx</p>
</div>
<div className="card" >
<a target="_blank">
<img alt='avatar' src="https://avatars.githubusercontent.com/u/6412038?v=3" style={{ width: '100px' }} />
</a>
<p className="card-text">xxx</p>
</div>
</div>
)
}
}
- 修改类名和样式以后不在提示
3 axios请求github接口
我们自定义样式,都是些的List组件的样式,我们直接把样式放置在List对应的组件处,List组件引入样式。
流程梳理:search请求github接口,返回数据;把数据传递给List组件用于展示。
Search组件和List组件属于兄弟组件,传值目前我们需要通过其父组件App来传递。
第一步:App组件初始化用户数组状态
state = {
githubUsers: [], // 初始化状态,github用户
}
第二步:Search请求后端接口,后端请求github接口返回数据;数据返回后,把数据传递给App。代码3-2如下所示:
// Search组件
import React, { Component } from 'react'
import axios from 'axios'
export default class Search extends Component {
search = () => {
// 获取用户输入
const {keyElement: {value: keyword}} = this
// 发起网络请求
axios.get(`/api1/search/users?q=${keyword}`).then(
resp => {
// console.log('请求成功',resp.data);
const data = resp.data.items.map(item => {
return {id: item.id, avatar: item.avatar_url, homePage: item.html_url, username: item.login}
})
this.props.updateAppState(data)
},
error => {
// console.log('请求失败', err);
}
)
}
render() {
return (
<section className="jumbotron">
<h3 className="jumbotron-heading">搜索github用户</h3>
<div>
<input ref={c => this.keyElement = c} type="text" placeholder="输入用户名" />
<button onClick={this.search}>搜索</button>
</div>
</section>
)
}
}
// App组件
/**
* 更新用户状态数据
* @param {object} githubUsers
*/
updateAppState = (githubUsers) => {
// 更新用户
this.setState({githubUsers})
}
<Search updateAppState={this.updateAppState}/>
第三步:App把数据传递给List,展示数据,代码3-3如下所示
// App 组件
<List {...this.state}/>
// List 组件
render() {
const { isFirst, isLoading, githubUsers, err } = this.props
return (
<div className="row">
{
githubUsers.map(item => {
return (
<div className="card" key={item.id}>
<a href={item.homePage} target="_blank" rel="noreferrer">
<img alt='avatar' src={item.avatar} style={{ width: '100px' }} />
</a>
<p className="card-text">{item.username}</p>
</div>
)
})
}
</div>
)
}
第四步:配置代理,setupProxy.js代码3-4如下
const { createProxyMiddleware } = require("http-proxy-middleware")
module.exports = function (app) {
app.use(
createProxyMiddleware("/api1",{
target: "http://localhost:5000", //配置转发目标地址(能返回数据的服务器地址)
changeOrigin: true, //控制服务器接收到的请求头中host字段的值
pathRewrite: { "^/api1": "" },
})
)
}
4 优化案例
虽然点击搜索能实现效果了但是,存在一些问题:
- 列表初始需要展示欢迎或者提示信息;
- 当开始请求后,数据未返回前,展示加载信息;
- 数据请求成功后,展示用户信息;数据请求失败,展示错误信息。
这时候我们需要拓展App中的状态数据如下所示:
state = {
githubUsers: [], // 初始化状态,github用户
isFirst: true, // 是否第一次打开页面
isLoadign: false, // 数据是否加载中
err: '', // 存储相关的错误信息
}
Search组件相应的做出调整如下:
search = () => {
// 获取用户输入
const {keyelement: {value: keyword}} = this
// console.log(keyword);
// 发送请求前通知App更新状态
this.props.updateAppState({isFirst: false, isLoading: true})
// 发起网络请求
axios.get(`/api1/search/users?q=${keyword}`).then(
resp => {
// console.log('请求成功',resp.data);
const data = resp.data.items.map(item => {
return {id: item.id, avatar: item.avatar_url, homePage: item.html_url, username: item.login}
})
this.props.updateAppState({isLoading: false, githubUsers: data})
},
error => {
// console.log('请求失败', err);
this.props.updateAppState({isLoading: false, err: error.message})
}
)
}
List组件展示根据数据,调整展示如下:
render() {
const { isFirst, isLoading, githubUsers, err } = this.props
return (
<div className="row">
{
isFirst ? <h2>欢迎使用,输入github用户名,点击搜索</h2> :
isLoading ? <h2>Loading......</h2> :
err ? <h2 style={{color: 'red'}}>{err}</h2> :
githubUsers.map(item => {
return (
<div className="card" key={item.id}>
<a href={item.homePage} target="_blank" rel="noreferrer">
<img alt='avatar' src={item.avatar} style={{ width: '100px' }} />
</a>
<p className="card-text">{item.username}</p>
</div>
)
})
}
</div>
)
}
关于脚手架设置代理请求真实网络数据小案例,讲解完毕。我们之前兄弟之间传递数据非常的麻烦,下面我们将要学习消息发布和订阅来解决这个问题。
结语
❓QQ:806797785
⭐️源代码仓库地址:https://github.com/gaogzhen/react-staging.git
参考:
[1]React视频教程[CP/OL].2020-12-15.p65-66.
[2]React官网[CP/OL].
[2]ChatGPT[CP/OL].