0303github搜索案例-react应用
文章目录
-
- 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/usersvalue: function () {}
*/
app.get("/search/users", function (req, res) {const {q} = req.queryaxios({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 Appextends Component {render() {// const { githubUsers } = this.statereturn (<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.propsreturn (<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.propsreturn (<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.propsreturn (<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].