react-github案例

github案例

一 react脚手架配置代理_方法一

需要理解的概念有:

  • axios模块的安装与使用
  • 什么是跨域
  • 跨域的解决方案有哪些
  • proxy的限制有什么

https://cra.docschina.org/docs/proxying-api-requests-in-development

测试代理服务器项目:http://qn.chinavanes.com/test_proxy_server.zip

在package.json中追加如下配置

"proxy":"http://localhost:5000"

说明:

  1. 优点:配置简单,前端请求资源时可以不加任何前缀。
  2. 缺点:不能配置多个代理。
  3. 工作方式:上述方式配置代理,当用Ajax请求了3000不存在的资源时,那么该请求会转发给5000 (优先匹配前端资源)

src/App.js

import React, { Component } from 'react';
import axios from 'axios';
class App extends Component {
	render() {
		// 解构赋值
		return 
; } componentDidMount() { this.getData(); } getData = () => { axios.get('/students').then((res) => { console.log(res); }); }; } export default App;

package.json

proxy不能是数组,只能是单一代理地址,不能代理多个。

{
     
  "name": "hello-react",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
     
    "@testing-library/jest-dom": "^5.11.4",
    "@testing-library/react": "^11.1.0",
    "@testing-library/user-event": "^12.1.10",
    "axios": "^0.21.1",
    "nanoid": "^3.1.23",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-scripts": "4.0.3",
    "web-vitals": "^1.0.1"
  },
  "scripts": {
     
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
     
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
     
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
     
    "@babel/plugin-transform-runtime": "^7.14.2",
    "@babel/preset-flow": "^7.13.13"
  },
  "proxy": "http://localhost:5000"
}

二 react脚手架配置代理_方法二

需要理解的概念有:

  • 代理中间件的使用
  1. 第一步:创建代理配置文件

    在src下创建配置文件:src/setupProxy.js
    
  2. 编写setupProxy.js配置具体代理规则:

    const proxy = require('http-proxy-middleware')
    // 默认已经安装,不需要再安装
    
    module.exports = function (app) {
           
    	app.use(
    		'/demo', //请求前缀,代理服务器只有遇到端口号后面带有/api的请求才会转发给服务器
    		proxy({
           
    			target: 'http://localhost:5000', //配置真正服务器的地址
    			changeOrigin: true, //该配置写不写无所谓
    			pathRewrite: {
            '^/demo': '' },
    		})
    	);
    	app.use(
    		'/test', //请求前缀,代理服务器只有遇到端口号后面带有/api的请求才会转发给服务器
    		proxy({
           
    			target: 'http://localhost:5001', //配置真正服务器的地址
    			changeOrigin: true, //该配置写不写无所谓
    			pathRewrite: {
            '^/test': '' },
    		})
    	);
    };
    

说明:

  1. 优点:可以配置多个代理,可以灵活的控制请求是否走代理。
  2. 缺点:配置繁琐,前端请求资源时必须加前缀。

src/App.js

import React, { Component } from 'react';
import axios from 'axios';
class App extends Component {
	render() {
		// 解构赋值
		return 
; } componentDidMount() { this.getData(); } getData = () => { axios.get('/demo/students').then((res) => { console.log(res); }); }; } export default App;

三 github搜索案例_静态页面

需要理解的概念有:

  • 组件的拆分
  • 静态资源的引入位置
  • className与style的应用
  • a标签rel='noreferrer’的配合
  • img标签alt属性的设置

静态页面:http://qn.chinavanes.com/users_page.zip

react-github案例_第1张图片

src/App.js

import React, { Component } from 'react';
import Search from './components/Search';
import List from './components/List';

class App extends Component {
	render() {
		return (
			
); } } export default App;

src/components/Search/index.js

import React, { Component } from 'react';

export default class Search extends Component {
	render() {
		return (
			

Search Github Users

 
); } }

src/components/List/index.js

import React, { Component } from 'react';
import './index.css';

export default class List extends Component {
	render() {
		return (
			
avatar

reactjs

); } }

src/components/List/index.css

.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%;
}

public/index.html

DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8" />
  <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>React Apptitle>
  <link rel="stylesheet" href="./css/bootstrap.css">
head>

<body>
  <div id="root">div>
body>

html>

四 github搜索案例_axios发送请求

需要理解的概念有:

  • input对象的获取,ref的三种操作方式:字符串、回调、createRef
  • axios的请求
  • github服务器端开放了cors,所以没有跨域问题

1.回调函数的ref设置应用

src/components/Search/index.js

import React, { Component } from 'react';
import axios from 'axios';

export default class Search extends Component {
	search = () => {
		const {
			keywordElement: { value: keyword },
		} = this; // 解构+赋值别名

		// 关键字可以尝试用`atguigu`
		axios.get(`https://api.github.com/search/users?q=${keyword}`).then(
			(res) => {
				console.log(res);
			},
			(err) => {
				console.log(err);
			}
		);
	};
	render() {
		return (
			

搜索github用户

(this.keywordElement = c)} type='text' placeholder='请输入搜索的用户名称' />  
); } }

2.createRef的ref设置应用

src/components/Search/index.js

import React, { Component } from 'react';
import axios from 'axios';

export default class Search extends Component {
	keyword = React.createRef();

	search = () => {
		const {
			current: { value: keyword },
		} = this.keyword; // 解构+赋值别名

		// 关键字可以尝试用`atguigu`
		axios.get(`https://api.github.com/search/users?q=${keyword}`).then(
			(res) => {
				console.log(res);
			},
			(err) => {
				console.log(err);
			}
		);
	};

	render() {
		return (
			

搜索github用户

 
); } }

五 github搜索案例_展示数据

需要理解的概念有:

  • 属性的传递,数组与函数
  • map与forEach的差异
  • 循环时key的设置

src/App.js

import React, { Component } from 'react';
import Search from './components/Search';
import List from './components/List';

class App extends Component {
	state = { users: [] };

	saveUsers = (users) => {
		this.setState({ users });
	};

	render() {
		const { users } = this.state;
		return (
			
); } } export default App;

src/components/Search/index.js

import React, { Component } from 'react';
import axios from 'axios';

export default class Search extends Component {
	keyword = React.createRef();

	search = () => {
		const {
			current: { value: keyword },
		} = this.keyword; // 解构+赋值别名

		// 关键字可以尝试用`atguigu`
		axios.get(`https://api.github.com/search/users?q=${keyword}`).then(
			(res) => {
				console.log(res);
				this.props.saveUsers(res.data.items);
			},
			(err) => {
				console.log(err);
			}
		);
	};

	render() {
		return (
			

搜索github用户

 
); } }

src/components/List/index.js

import React, { Component } from 'react';
import './index.css';

export default class List extends Component {
	render() {
		const { users } = this.props;
		return (
			
{users.map((userObj) => (
avatar

{userObj.login}

))}
); } }

六 github搜索案例_完成案例

需要理解的概念有:

  • 请求的不同状态,加载中,加载完成,加载错误
  • 展开式批量参数传递
  • 解构赋值
  • 三元运算的应用

src/App.js

import React, { Component } from 'react';
import Search from './components/Search';
import List from './components/List';

class App extends Component {
	state = {
		users: [],
		isFirst: true, // 是否第一次打开
		isLoading: false, // 是否显示isLoading
		err: '', // 错误提示内容
	};

	updateAppState = (stateObj) => {
		this.setState(stateObj);
	};

	render() {
		return (
			
); } } export default App;

src/components/Search/index.js

import React, { Component } from 'react';
import axios from 'axios';

export default class Search extends Component {
	keyword = React.createRef();

	search = () => {
		const {
			current: { value: keyword },
		} = this.keyword; // 解构+赋值别名

		// 发送请求前通知App更新状态
		this.props.updateAppState({ isFirst: false, isLoading: true });

		// 关键字可以尝试用`atguigu`
		axios.get(`https://api.github.com/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 });
			}
		);
	};

	render() {
		return (
			

搜索github用户

 
); } }

src/components/List/index.js

import React, { Component } from 'react';
import './index.css';

export default class List extends Component {
	render() {
		const { isFirst, isLoading, err, users } = this.props;
		return (
			
{isFirst ? (

欢迎使用,输入关键字,随后点击搜索

) : isLoading ? (

Loading...

) : err ? (

{err.toString()}

) : ( users.map((userObj) => (
avatar

{userObj.login}

)) )}
); } }

七 消息订阅与发布技_pubsub

需要理解的概念有:

  • 订阅及发布模式
  • 事件的发布与订阅
  • 生命周期钩子函数
  • 组件的嵌套与层次结构

src/App.js

import React, { Component } from 'react';
import Search from './components/Search';
import List from './components/List';

class App extends Component {
	render() {
		return (
			
); } } export default App;

src/components/Search/index.js

import React, { Component } from 'react';
import axios from 'axios';
import PubSub from 'pubsub-js';

export default class Search extends Component {
	keyword = React.createRef();

	search = () => {
		const {
			current: { value: keyword },
		} = this.keyword; // 解构+赋值别名

		// 发送请求前通知List更新状态
		PubSub.publish('pubsubEvent', { isFirst: false, isLoading: true });

		// 关键字可以尝试用`atguigu`
		axios.get(`https://api.github.com/search/users?q=${keyword}`).then(
			(res) => {
				// 请求成功以后通知List更新状态
				PubSub.publish('pubsubEvent', { isLoading: false, users: res.data.items });
			},
			(err) => {
				// 请求失败以后通知List更新状态
				PubSub.publish('pubsubEvent', { isLoading: false, err: err });
			}
		);
	};

	render() {
		return (
			

搜索github用户

 
); } }

src/components/List/index.js

import React, { Component } from 'react';
import './index.css';

import PubSub from 'pubsub-js';

export default class List extends Component {
	state = {
		users: [],
		isFirst: true, // 是否第一次打开
		isLoading: false, // 是否显示isLoading
		err: '', // 错误提示内容
	};

	componentDidMount() {
		this.psEvent = PubSub.subscribe('pubsubEvent', (_, data) => {
			this.setState(data);
		});
	}

	componentWillUnmount() {
		PubSub.unsubscribe(this.psEvent);
	}

	render() {
		// this.props转成this.state
		const { isFirst, isLoading, err, users } = this.state;
		return (
			
{isFirst ? (

欢迎使用,输入关键字,随后点击搜索

) : isLoading ? (

Loading...

) : err ? (

{err.toString()}

) : ( users.map((userObj) => (
avatar

{userObj.login}

)) )}
); } }

八 fetch发送请求

需要理解的概念有:

  • ajax、axios、fetch之间的差异与区别

1.jQuery ajax

$.ajax({
     
   type: 'POST',
   url: url,
   data: data,
   dataType: dataType,
   success: function () {
     },
   error: function () {
     }
});

优势与不足点:

  • 本身是针对MVC的编程,不符合现在前端MVVM的浪潮
  • 基于原生的XHR开发,XHR本身的架构不清晰,已经有了fetch的替代方案
  • JQuery整个项目太大,单纯使用ajax却要引入整个JQuery非常的不合理(采取个性化打包的方案又不能享受CDN服务)

2.axios

axios({
     
    method: 'post',
    url: '/user/12345',
    data: {
     
        firstName: 'Fred',
        lastName: 'Flintstone'
    }
})
.then(function (response) {
     
    console.log(response);
})
.catch(function (error) {
     
    console.log(error);
});

优势与不足点:

  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 客户端支持防止CSRF
  • 提供了一些并发请求的接口(重要,方便了很多的操作)

3.fetch

try {
     
  let response = await fetch(url);
  let data = response.json();
  console.log(data);
} catch(e) {
     
  console.log("Oops, error", e);
}

优势与不足点:

  • 符合关注分离,没有将输入、输出和用事件来跟踪的状态混杂在一个对象里
  • 更好更方便的写法
  • 更加底层,提供的API丰富(request, response)
  • 脱离了XHR,是ES规范里新的实现方式
    1)fetchtch只对网络请求报错,对400,500都当做成功的请求,需要封装去处理
    2)fetch默认不会带cookie,需要添加配置项
    3)fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了量的浪费
    4)fetch没有办法原生监测请求的进度,而XHR可以

为什么要用axios?

axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,它本身具有以下特征:

  • 从浏览器中创建 XMLHttpRequest
  • 从 node.js 发出 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求和响应数据
  • 取消请求
  • 自动转换JSON数据客户端支持防止CSRF/XSRF

九 总结github搜索案例

需要理解的概念有:

1.拆分静态组件,设计状态时要考虑全面,例如带有网络请求的组件,要考虑请求失败怎么办
2.分析得知:Search组件负责搜索,List组件负责展示,状态要交给App
3.List组件不仅要展示用户信息,还要展示:欢迎词、loading、错误信息
4.在App中设计一个方法:getSearchInfo去更新App的状态,一个一个写太麻烦
5.批量的给List组件传递参数:
6.在List中用三目运算符进行连续判断,从而决定List组件展示什么
7.先订阅,再发布(理解:有一种隔空对话的感觉)
8.适用于任意组件间通信
rror", e);
}




优势与不足点:

- 符合关注分离,没有将输入、输出和用事件来跟踪的状态混杂在一个对象里
- 更好更方便的写法
- 更加底层,提供的API丰富(request, response)
- 脱离了XHR,是ES规范里新的实现方式
  1)fetchtch只对网络请求报错,对400,500都当做成功的请求,需要封装去处理
  2)fetch默认不会带cookie,需要添加配置项
  3)fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了量的浪费
  4)fetch没有办法原生监测请求的进度,而XHR可以

**为什么要用axios?**

axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,它本身具有以下特征:

- 从浏览器中创建 XMLHttpRequest
- 从 node.js 发出 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求和响应数据
- 取消请求
- 自动转换JSON数据客户端支持防止CSRF/XSRF

# 九 总结github搜索案例

需要理解的概念有:

1.拆分静态组件,设计状态时要考虑全面,例如带有网络请求的组件,要考虑请求失败怎么办
2.分析得知:Search组件负责搜索,List组件负责展示,状态要交给App
3.List组件不仅要展示用户信息,还要展示:欢迎词、loading、错误信息
4.在App中设计一个方法:getSearchInfo去更新App的状态,一个一个写太麻烦
5.批量的给List组件传递参数:``
6.在List中用三目运算符进行连续判断,从而决定List组件展示什么
7.先订阅,再发布(理解:有一种隔空对话的感觉)
8.适用于任意组件间通信
9.componentDidMount中订阅消息,要在组件的componentWillUnmount中进行取消订阅

你可能感兴趣的:(react)