React全家桶: github搜索案例_详细拆解

简介: React全家桶: github搜索案例_详细拆解

写在前面

在最近看了React之后,一直觉得学的懵懵然,虽然很多大佬的手写笔记,写的都很不错,但是我一直没有我想要的那种细无巨细,比如类式组件this指向问题的追根溯源,又比如三大实例属性简写的由来,总之我还是决定做一份事无巨细的笔记。

那就让我们开始吧!


github搜索案例_静态组件

4da4dd0056f64d27af6c90fbeb9e70b1_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.gif


拆分组件

App组件、Search组件、List组件


静态页面拆分

  • 将静态页面全部复制到App组件,进行详细拆分。

对class、fontsize、style等关键字进行替换为className、fontSize、style={{}}。

  • 创建index.css文件,将全部css样式引入,在List组件中引入样式文件。实现样式加工。
  • 将对应的html拆分到子组件内部,在List组件中引入然后使用。
  • 引入bootstrap

①在public文件夹下面创建一个css文件添加bootstrap.css

②在index.html中引入bootstrap.css

<link rel="stylesheet" href="/css/bootstrap.css">
复制代码
  • 创建component文件夹

在component文件夹下面创建不同的子组件文件夹。


添加rel="noreferrer"

1.超链接 target="_blank" 要增加 rel="nofollow noopener noreferrer" 来堵住钓鱼安全漏洞。如果你在链接上使用 target="_blank"属性,并且不加上rel="noopener"属性,那么你就让用户暴露在一个非常简单的钓鱼攻击之下。

// a标签下添加  *rel* = "noreferrer"
 <a *href*="https://github.com/reactjs" *target*="_blank"  *rel* = "noreferrer">
复制代码


7dbd465085cd46d7b8a44e4873b8e21e_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


92236168adab462baf7b517789bea118_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


img标签

  • img图片 alt属性值最后不要使用photo,picture,img等等。脚手架检查会觉得不规范。

8cda0ed3659a4163ab0594fbb46d9d65_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


github搜索案例_axios发送请求

修改Search组件

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>
        )
}
复制代码


书写点击事件,获取input输入值

  • 使用ref、onclick
search = ()=>{
    // 获取用户输入的值
      console.log("this.keyWordElement.value")
}
<input ref={c => this.keyWordElement = c} type="text" placeholder="输入关键词点击搜索"/>&nbsp;
<button onClick={this.search}>搜索</button>
复制代码


  • 解构赋值连续写法
//获取用户的输入(连续解构赋值+重命名)
const {keyWordElement:{value:keyWord}} = *this*
console.log(value) // === console.log(keyWord)
console.log(keyWordElement) // Error
复制代码


Axios请求

  1. 引入Axios
import axios from 'axios'
复制代码
  1. 使用ref,onClick事件函数绑定input标签和button标签。


github 多次访问失效

  • 解决方式

开启一个端口号为5000的服务器。对github发送请求的时候,会通过该服务器进行请求。

在多次访问之后无法从github获取数据时,服务器会直接返回本身的数据到客户端。

  • 跨域

后端使用cors解决了跨域问题

  • 对端口号为5000的服务器配置代理
const proxy = require('http-proxy-middleware')
module.exports = function(app){
  app.use(
    proxy('/api1',{ //遇见/api1前缀的请求,就会触发该代理配置
      target:'http://localhost:5000', //请求转发给谁
      changeOrigin:true,//控制服务器收到的请求头中Host的值
      pathRewrite:{'^/api1':''} //重写请求路径(必须)
    })
  )
}
复制代码

请求地址为:http://localhost:3000/api1/search/users?q=${keyWord}


github搜索案例_展示数据

父组件初始化状态

  • 父组件App.js

使用父组件写方法和初始化status,子组件使用方法更新status的手段将获得的用户信息反馈到界面。

// 父组件App
state = {
        users:[]
    }
    saveUsers = (users)=> {
this.setState({users})
}
复制代码


  • 子组件Search组件

调用函数改变状态

<Search updateAppState={this.updateAppState} />
复制代码


search = ()=>{
        //获取用户的输入(连续解构赋值+重命名)
        const {keyWordElement:{value:keyWord}} = this
        //发送网络请求
        axios.get(`/api1/search/users?q=${keyWord}`).then(
                response => {
                        //请求成功后通知App更新状态
                        this.props.saveUsers(response.data.items);
                },
                error => {
                        //请求失败后通知App更新状态
                        this.props.updateAppState({isLoading:false,err:error.message})
                }
        )
}
复制代码


子组件渲染

  • List组件
<List {...this.state}/>
复制代码


return (
        <div className="row">
                {
                        users.map((userObj)=>{
                                return (
                                        <div key={userObj.id} className="card">
                                                <a rel="noreferrer" href={userObj.html_url} target="_blank">
                                                        <img alt="head_portrait" src={userObj.avatar_url} style={{width:'100px'}}/>
                                                </a>
                                                <p className="card-text">{userObj.login}</p>
                                        </div>
                                )
                        })
                }
        </div>
)
复制代码


github搜索案例_完成案例

为了完善功能,第一次请求,加载中,加载失败等等更新status。

子组件Search调用了2次updateAppState方法,子组件List使用了嵌套三元符分别展示不同页面


初始化状态

  • 添加加载中、初次打开页面状态
state = { //初始化状态
        users:[], //users初始值为数组
        isFirst:true, //是否为第一次打开页面
        isLoading:false,//标识是否处于加载中
        err:'',//存储请求相关的错误信息
} 
复制代码


  • 书写更新状态的函数 updateAppState
//更新App的state
    updateAppState = (stateObj)=>{
this.setState(stateObj)
}
复制代码


  • 向Search组件传递 updateAppState
<Search updateAppState={this.updateAppState} />
复制代码


  • 向List组件传递状态属性。
<List {...this.state}/>
复制代码


  • 子组件Search发送请求成功后调用updateAppState函数
//发送请求前通知App更新状态
this.props.updateAppState({isFirst:false,isLoading:true}) //一旦请求就开始改变
复制代码


  • 请求成功后通知App更新状态
//子组件Search
//发送网络请求
axios.get(`/api1/search/users?q=${keyWord}`).then(
    response => {
        //请求成功后通知App更新状态
this.props.updateAppState({isLoading:false,users:response.data.items})
    },
    error => {
        //请求失败后通知App更新状态
         this.props.updateAppState({isLoading:false,err:error.message}) // 不能传递对象
    }
)
复制代码


  • 不能传递对象
this.props.updateAppState({isLoading:false,err:error.message}) // 不能传递对象
复制代码

b824489e6f944423aef2539c3fc982ac_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • 根据不同状态时刻,展示不同页面
    1.初次打开页面
    2.加载中
    3.加载失败
    4.加载成功
<div className="row">
        {
                // 初次打开页面
                isFirst ? <h2>欢迎使用,输入关键字,随后点击搜索</h2> :
                // 加载中
                isLoading ? <h2>Loading......</h2> :
                //加载失败
                err ? <h2 style={{color:'red'}}>{err}</h2> :
                //加载成功
                users.map((userObj)=>{
                        return (
                                <div key={userObj.id} className="card">
                                        <a rel="noreferrer" href={userObj.html_url} target="_blank">
                                                <img alt="head_portrait" src={userObj.avatar_url} style={{width:'100px'}}/>
                                        </a>
                                        <p className="card-text">{userObj.login}</p>
                                </div>
                        )
                })
        }
</div>
复制代码


消息订阅与发布技_pubsub

github搜索案例 修改升级

工具库: PubSubJS

下载: npm install pubsub-js --save

使用:

1) import PubSub from 'pubsub-js' //引入
2) PubSub.subscribe('delete', function(data){ }); //订阅
3) PubSub.publish('delete', data) //发布消息
复制代码


1.将App组件的状态更改到List组件

state = { //初始化状态
        users:[], //users初始值为数组
        isFirst:true, //是否为第一次打开页面
        isLoading:false,//标识是否处于加载中
        err:'',//存储请求相关的错误信息
} 
const {users,isFirst,isLoading,err} = this.state
复制代码


2.将App的函数,状态全部清除

export default class App extends Component {
  render() {
    return (
      <div className="container">
        <Search/>
        <List/>
      </div>
    )
  }
}
复制代码


3. 引入pubsub并且挂载组件之后订阅消息

  • List组件订阅消息
import PubSub from 'pubsub-js'
componentDidMount(){
        this.token = PubSub.subscribe('atguigu',(_,stateObj)=>{
                this.setState(stateObj)
        })
}
复制代码


4.引入pubsub并且挂载组件之后发布消息

import PubSub from 'pubsub-js'
search = ()=>{
        //获取用户的输入(连续解构赋值+重命名)
        const {keyWordElement:{value:keyWord}} = this
        //发送请求前通知List更新状态
        PubSub.publish('atguigu',{isFirst:false,isLoading:true})
        //发送网络请求
        axios.get(`/api1/search/users?q=${keyWord}`).then(
                response => {
                        //请求成功后通知List更新状态
                        PubSub.publish('atguigu',{isLoading:false,users:response.data.items})
                },
                error => {
                        //请求失败后通知App更新状态
                        PubSub.publish('atguigu',{isLoading:false,err:error.message})
                }
        )
}
复制代码


e67484f052f14810a3cd0fea927b4def_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


组件将要卸载取消订阅消息

componentWillUnmount(){
        PubSub.unsubscribe(this.token)
}
复制代码


fetch发送请求

发送AJAX请求方式

  1. xhr对象

传送门:www.html.cn/doc/ajax/xm…

2.jQuery(对象xhr封装,使用回调)

传送门:jquery.com/

优点:封装了请求

缺点:产生回调地狱

3.Axios(,对象xhr封装,promise风格)


Fetch

1.window对象自带
2.不用下载,浏览器中直接使用
3.promise风格
复制代码

由于一些不可抗力因素,比如断网d04e1e611ce842b9b6deb95d3e88dcf3_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • response.json

返回一个Promise实例对象。

1.获取数据成功

这个Promise对象保存获取的数据

  1. 获取数据失败

这个Promise对象保存了失败的原因

feb3dec5c62c433b9066dc66b3c39c15_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


f678cbfe144e4fd1861285ccf27e6f8d_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


.then 链式调用

  • .then 的返回值就是一个Promise实例对象,可以继续调用 .then。
//发送网络请求---使用fetch发送(未优化)
 fetch(`/api1/search/users2?q=${keyWord}`).then(
        response => {
                console.log('联系服务器成功了');
                return response.json()
        },
        error => {
                console.log('联系服务器失败了',error);
                return new Promise(()=>{})
        }
).then(
        response => {console.log('获取数据成功了',response);},
    error => {console.log('获取数据失败了',error);}
复制代码


  • 发送网络请求---使用fetch发送(优化)
//发送网络请求---使用fetch发送(优化)
try {
        const response= await fetch(`/api1/search/users2?q=${keyWord}`)
        const data = await response.json()
        console.log(data);
        PubSub.publish('atguigu',{isLoading:false,users:data.items})
} catch (error) {
        console.log('请求出错',error);
        PubSub.publish('atguigu',{isLoading:false,err:error.message})
}
复制代码


fetch特点

1. fetch: 原生函数,不再使用XmlHttpRequest对象提交ajax请求

2. 老版本浏览器可能不支持

3. 关注分类,只要联系上了服务器就会显示访问成功,而不管是404还是什么(路径有问题)。断网等等不可抗力因数会到时联系服务器失败。

4. Respone原生对象上又一个json方法。



目录
相关文章
|
6月前
|
Java Spring
GitHub 上搜索开源项目技巧
GitHub 上搜索开源项目技巧
82 0
|
6月前
|
前端开发
React查询、搜索类功能的实现
React查询、搜索类功能的实现
63 0
|
3月前
|
存储 前端开发 JavaScript
最适合新手学习的react案例-Todolist尊享版!
【8月更文挑战第13天】最适合新手学习的react案例-Todolist尊享版!
57 2
最适合新手学习的react案例-Todolist尊享版!
|
2月前
|
前端开发
React技术栈-react使用的Ajax请求库实战案例
这篇文章介绍了在React应用中使用Axios和Fetch库进行Ajax请求的实战案例,展示了如何通过这些库发送GET和POST请求,并处理响应和错误。
54 10
React技术栈-react使用的Ajax请求库实战案例
|
2月前
|
前端开发
React技术栈-react使用的Ajax请求库用户搜索案例
这篇文章展示了一个React技术栈中使用Ajax请求库(如axios)进行用户搜索的实战案例,包括React组件的结构、状态管理以及如何通过Ajax请求获取并展示GitHub用户数据。
32 7
React技术栈-react使用的Ajax请求库用户搜索案例
|
2月前
|
前端开发 NoSQL MongoDB
React技术栈-基于react脚手架编写评论管理案例
这篇文章介绍了在MongoDB中使用sort和投影来对查询结果进行排序和限制返回的字段,通过具体的命令示例展示了如何实现这些操作。
50 6
React技术栈-基于react脚手架编写评论管理案例
|
30天前
|
JSON JavaScript 前端开发
《进阶篇第7章》学习vue中的ajax之后,练习vue案例-github用户搜索案例
《进阶篇第7章》学习vue中的ajax之后,练习vue案例-github用户搜索案例
15 0
|
2月前
|
前端开发 JavaScript
React技术栈-react的脚手架创建应用案例
本文介绍了如何使用React的官方脚手架工具create-react-app快速创建React项目,并展示了项目的目录结构和基本的代码文件,以及如何启动和运行React应用。
32 2
|
4月前
|
人工智能 数据挖掘 大数据
爆赞!GitHub首本标星120K的Python程序设计人工智能案例手册
为什么要学习Python? Python简单易学,且提供了丰富的第三方库,可以用较少的代码完成较多的工作,使开发者能够专注于如何解决问题而只花较少的时间去考虑如何编程。此外,Python还具有免费开源、跨平台、面向对象、胶水语言等优点,在系统编程、图形界面开发、科学计算、Web开发、数据分析、人工智能等方面有广泛应用。尤其是在数据分析和人工智能方面,Python已成为最受开发者欢迎的编程语言之一,不仅大量计算机专业人员选择使用Python进行快速开发,许多非计算机专业人员也纷纷选择Python语言来解决专业问题。 由于Python应用广泛,关于Python的参考书目前已经有很多,但将Pytho
|
5月前
|
Python 容器
GitHub狂揽6700 Star,Python进阶必备的案例、技巧与工程实践
当下是 Python 急剧发展的时代,越来越多的人开始学习和使用Pyhon,而大家也遇到了各种问题。这份手册清晰、细致地介绍了 Python 代码应该遵循的编程风格,并解释了背后的原理和机制。