基于zty
1 为什么要应用React
原生JavaScript的毛病
- 原生JavaScript操作DOM繁琐,效率低(DOM-API操作UI)
- 应用JavaScript间接操作DOM,浏览器会进行大量的重绘重排
- 原生JavaScript没有组件化编码方案,代码复用率很低
重绘(repaint):当一个元素的外观产生扭转,但没有扭转布局,从新把元素外观绘制进去的过程,叫做重绘
重排(reflow):当DOM的变动影响了元素的几何信息(DOM对象的地位和尺寸大小),浏览器须要从新计算元素的几何属性,将其安放在界面中的正确地位,这个过程叫做重排
重绘 重排 :https://juejin.cn/post/684490...
- 开发迅速。React组件化的个性使得React能够在我的项目中大量复用封装好的组件,进步代码的复用率,缩小了反复写雷同代码的繁琐而无聊的工作
- 原生的JavaScript操作DOM繁琐,效率低(DOM-API操作UI)
- 应用JavaScript,包含jQuery间接操作DOM,浏览器会进行大量的重绘和重排(尽管jQuery简化了操作DOM的步骤,但仍然效率低下)
- 原生的JavaScript没有组件化编码方案,代码复用率低
- 生态绝对欠缺。React 起源于 Facebook 的外部我的项目,具备绝对稳固的保护,周边生态绝对欠缺,像各种的UI库,路由库等,能够在更少的工夫内实现更多的工作。
- 有大公司作为背书。除了React的开发公司Faceboook大量应用React外,国内外还有很多大公司也广泛应用React,在国外有Paypal,Airbnb等,在国内有阿里,腾讯,字节跳动等。
- 有弱小的开源社区。开源我的项目的社区十分重要,在社区开发者的奉献下会让一些开源我的项目变得越来越好,我的项目的issue的解决速度也会失去晋升,同时还会提供大量的周边技术工具和技术博客。
模块化与组件化
模块:向外提供特定性能的js程序, 个别就是一个js文件
为什么要拆成模块:随着业务逻辑减少,代码越来越多且简单。
作用:复用js, 简化js的编写, 进步js运行效率组件:用来实现部分性能成果的代码和资源的汇合(html/css/js/image等等)
为什么要用组件: 一个界面的性能更简单
作用:复用编码, 简化我的项目编码, 进步运行效率
模块化:当利用的js都以模块来编写的, 这个利用就是一个模块化
的利用
组件化:当利用是以多组件的形式实现, 这个利用就是一个组件化
的利用
2 React的定义
React的定义:用于==构建用户界面==的==JavaScript库==。
关键字:
- 构建用户界面:阐明React专一于视图的构建,既不是一个申请库,也不是一个打包工具,而是次要提供UI层面的解决方案。
- JavaScript库:这阐明React并不是一个框架,并不能解决我的项目中的所有问题,为了在我的项目中应用它,须要联合其余的库,例如Redux/React-router等来帮助提供残缺的解决方案。在这些周边生态的配合下能力组合成一个框架
换句话来说,React所做的有三步
- 发送申请取得数据
- 解决数据(过滤,整顿格局等)
- 操作DOM出现页面
也就是说React也能够定义为一个将数据渲染为HTML视图的开源JavaScript库。
3 React的个性
- 申明式编程:
命令式编程 VS 申明式编程:
简略来说,命令式编程就是通过代码来通知计算机去做什么。
而申明式编程是通过代码来通知计算机你想要做什么,让计算机想出如何去做。
举个生存中的例子就是:
命令式编程:我想喝一个冰可乐,而后我就会对身边的XXX说:“XXX,你去厨房,关上冰箱,拿出一瓶冰可乐,关上之后送过来给我。”
申明式编程:我想喝一个冰可乐,而后我就会对身边的XXX说:“XXX,我想喝冰可乐。”而具体他是怎么拿到的冰可乐,怎么送过来的,是下楼买的还是在冰箱里拿的,我并不关怀,我只关怀我喝冰可乐的需要是否失去了满足。用代码来举个例子:
如果我要在界面上展现一个按钮,并且点击按钮后会扭转该按钮的class。
用DOM编程写的代码就是命令式编程:首先你要指挥浏览器,第一步先要找到id为container的节点,而后创立一个button element,接着给这个button增加一个class name,而后增加一个点击事件,最初将button增加到container节点里。这整个过程每一步操作都是命令式的,一步一步通知浏览器要做什么。
const container = document. getElementById ( "container" );const btn = document.createElement ("button");btn.className = "btn red " ;btn.textContent = "Demo" ;btn.onclick = function ( ) { if ( this.classList.contains ( "red" ) ) { this.classList.remove( "red" ); this.classList.add ( "blue" ); }else { this.classList.remove( "blue" ); this.classList.add ( "red" ); }};container.appendChild( btn);
而要实现雷同性能,采纳申明式编程的React就简略得多了。
首先咱们定义一个Button组件,在render函数里通过返回一个相似HTML的数据结构,通知React我要渲染一个Button,它是id为container的子节点。Button上的ClassName是动态变化的,当点击按钮时class要扭转,这样就能够了。至于render什么时候被执行,是如何渲染到页面上的,点击按钮之后classname是如何更新的,这些都不须要你关怀,你只须要通知React你心愿以后的UI应该是一个什么样的状态就能够了。
class Button extends React. Component { state = { color: "red" }; handleChange =()=> { const color = this.state.color == "red" ? "blue" : "red" ;this.setState({ color }); }; render( ) { return ( <div id="container"> <button className={ `btn ${this.state.color}` } onclick={this.handleChange} > Demo </button> </div> ); }}
- 组件化:React提供了一种全新的语法扩大,JSX。JSX创造性地将渲染逻辑和UI逻辑联合在了一起,而这个结合体在React中就被称为组件。一个页面由多个组件组成,甚至整个利用都能够视为一个组件,只不过是最大的组件。组件能够层层嵌套,一个组件能够由多个组件组成,一个大的组件由很多个小组件组成,这些小组件也有可能由更小的组件组成。同一个组件可能会被应用在不同的中央。
组件化的呈现大幅度地晋升了代码地复用率,同时也扭转了前端开发人员的一个编程思维 - 一次学会,随处编写:这句话的意思不是学会了想写什么就能够写什么,也不是说写一次想在哪里跑就在哪里跑,而是说学会后能够在很多中央应用React的语法来写代码,比方配合React DOM来编写web端的页面,配合React Native来写手机客户端APP,配合React 360开发VR界面等。
React的灵活性是因为它本身的定位决定的。React是一个用于构建用户界面的JS库,对于React来说,这里的用户界面是一个形象的虚构的用户界面,其实就是一个形容页面状态的数据结构。web页面,挪动客户端页面,VR界面都是用户界面,只有配合相应的渲染器就能在不同的平台中展现正确的UI界面。
艰深来说,咱们能够把React的执行后果设想成一个视频文件数据,在不同的播放器设施,咱们通过转换器将视频编译成不同的格局来让他们在不同的播放器上失常地播放。所以在写web端React时咱们要额定引入React DOM来做渲染。
此外,React应用虚构DOM+优良的Diffing算法,尽量减少与实在DOM的交互,最小化页面重绘
- 在 React Native中能够应用React语法进行挪动端开发
- 应用虚构DOM+Diff算法,尽量减少与实在DOM的交互
React高效的起因
应用虚构(virtual)DOM, 不总是间接操作页面实在DOM。
DOM Diffing算法, 最小化页面重绘。4 React入门
4.0 相干库介绍
react.js:React外围库。
react-dom.js:提供操作DOM的React扩大库。
babel.min.js:解析JSX语法代码转为JS代码的库。浏览器不能间接解析JSX代码, 须要babel转译为纯JS的代码能力运行
只有用了JSX,都要加上type="text/babel", 申明须要babel来解决
4.1 hello_react
4.2 虚构DOM的创立
React.createElement()
创立虚构DOM的两种形式
纯JS形式(个别不必,过于繁琐)
const VDOM = React.createElement('h1',{id:'title'},React.createElement('span',{},'Hello,React'))
JSX形式(简略不便,就是js创立虚构DOM的语法糖。最终由babel翻译成js的模式,与用js写的后果一样)
const VDOM = <h1>Hello,React</h1>
虚构DOM和实在DOM
React提供一些API来创立一种“特地”的==个别js对象==
const VDOM = React.createElement('xx',{id:'xx'},'xx')///顺次为标签名,标签属性和标签内容
下面创立的就是一个简略的虚构DOM对象
- 咱们编码时根本只须要操作react的虚构DOM相干数据,react就会转换为实在的DOM
对于虚构DOM总结:
- 实质是Object类型的对象(个别对象)
- 虚构DOM比拟“轻”,实在DOM比拟“重”,因为虚构DOM是React外部在用,无需实在DOM上那么多的属性
- 虚构DOM对象最终都会被React转换为实在DOM,出现在页面上
- 渲染虚构DOM(元素)
语法: ReactDOM.render(virtualDOM, containerDOM)
作用: 将虚构DOM元素渲染到页面中的实在容器DOM中显示
参数阐明
参数一: 纯js或jsx创立的虚构dom对象
参数二: 用来蕴含虚构DOM元素的实在dom元素对象(个别是一个div)
4.3 JSX
链接:JSX根本语法规定
- 全称: JavaScript XML
- react定义的一种相似于XML的JS扩大语法: JS + XML,实质上还是JavaScript
- 是React.createElement(component, props, ...children)办法的语法糖
- 作用:用来简化创立虚构DOM
- 写法:var ele =<h1>Hello JSX!</h1>
- 它不是字符串(不要加引号),也不是HTML/XML标签
- 它最终产生的就是一个js对象
- 标签名任意:HTML标签或其余标签
- 标签属性随便:HTML标签属性或其它
- 根本语法规定
标签首字母
(1)若小写字母结尾,则将该标签转为HTML中同名元素,若HTML中无该标签对应的同名元素,则报错。
(2)若大写字母结尾,则react就去渲染对用的组件,若组件没有定义,则报错
标签中的==js表达式==必须用{ }蕴含
肯定要辨别:【JS语句(代码)】与【js表达式】
表达式:一个表达式会产生一个值,能够放在任何一个须要值的中央
上面这些都是表达式:
- a
- a+b
- demo(1) //函数调用表达式
- arr.map()
- function test() { }
语句(代码):不产生值
上面这些都是语句(代码):
- if(){}
- for(){}
- switch(){case:xxx}
- 正文须要写在花括号{}中
- 款式的类名指定不要写class,要写className
内联款式要用style={{key:value}}的模式写第一个{}示意外面是一个js表达式,第二个{}示意外面是一个键值对,外面要写小驼峰的模式, 比方font-size要写成fontSize
<span style={{color:'#e0e0e0', fontSize:18} }> myData</span>- 虚构DOM只能有一个根标签,有多个标签时,可用一个div包起来
- 标签必须闭合
- babel.js的作用
- 浏览器不能间接解析JSX代码, 须要babel转译为纯JS的代码能力运行
- 只有用了JSX,都要加上type="text/babel", 申明须要babel来解决
4.4 模块与组件,模块化与组件化的了解
- 模块
- 了解:向外提供特定性能的js程序,个别就是一个js文件
- 为什么要拆成模块:因为随着业务逻辑减少,代码越来越多且简单
- 作用:服用js,简化js的编写,进步js运行效率
- 组件
- 了解:用来实现部分性能的代码和资源的汇合(html/css/js/image等等)
- 为什么一个界面的性能很简单,不可能写成一整块,要分成一块块写,而后拼起来
- 作用:复用编码,简化我的项目编码,进步运行效率
模块化
当一个利用的js都是以模块来编写,这个利用就是一个模块化的利用
组件化
当利用是以多组件的形式实现,这个利用就是一个组件化的利用
5 React面向组件编程
5.1 根本了解和应用
组件的类型
- 函数式组件:用函数定义的组件,实用于简略组件的定义(没有实例,this=undefined)
留神:
(1)组件名必须首字母大写
(2)虚构DOM元素只能有一个根元素
(3)虚构DOM元素必须有完结标签
- 类式组件:用类定义的组件,实用于简单组件的定义(有实例)
简略组件:无状态的组件
简单组件:有状态(state)的组件
状态:举例子说
- 人是有状态的,比方明天的精力如何,人的状态会影响人的行为
- 组件也是有状态的,组件的状态驱动页面,数据放在状态里
5.2 组件实例的三大外围属性
5.2.1 state
- 了解:
- state是组件对象最重要的属性, 值是==对象(==能够蕴含多个key-value的组合),用{}包裹
- 组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(从新渲染组件)
- 留神:
- 组件中render办法中的this为组件实例对象
组件自定义的办法中this为undefined(作为事件的回调应用),如何解决?
- a) 强制绑定this: 通过函数对象的bind()
- b) 箭头函数【要写成赋值语句+箭头函数的模式,类外面不反对function(){ }这种模式】
- 状态数据,不能间接批改或更新,要用setState
5.2.2 props
- 了解:
- 每个组件对象都会有props(properties的简写)属性
- 组件标签的所有属性都保留在props中
- 作用
- 通过标签属性从组件内向组件内传递变动的数据
- 留神: 组件外部不要批改props数据
- 编码操作
- 外部读取某个属性值: this.props.name
对props中的属性值进行类型限度和必要性限度
第一种形式(React v15.5 开始已弃用):
Person.propTypes = { name: React.PropTypes.string.isRequired, age: React.PropTypes.number}
第二种形式(新):应用prop-types库进限度(须要引入prop-types库)
Person.propTypes = { name: PropTypes.string.isRequired, age: PropTypes.number. }
- 扩大属性:将对象的所有属性通过props传递:<Person {...person}/>
默认属性值:
Person.defaultProps = { age: 18, sex:'男'}
组件类的构造函数
constructor(props){ super(props) console.log(props)//打印所有属性}
5.2.3 ref
- 了解:组件内的标签能够定义ref属性来标识本人
- 编码
字符串模式的ref:(曾经不被react举荐应用)官网阐明
<input ref = 'input1'/>
回调模式的ref
<input ref={(c)=>{this.input1 = c}}
createRef创立ref容器
myRef = React.createRef() ;<input ref={this.myRef}/>
5.3 React中的事件处理
通过onXxx属性指定处理函数(留神大小写,与原生的js辨别开)
a) React应用的是自定义(合成)事件, 而不是应用的原生DOM事件 ——目标是为了更好的兼容性
b) React中的事件是通过事件委托形式解决的(委托给组件最外层的元素) ——目标是为了高效
通过event.target失去产生事件的DOM元素对象 ——为了防止适度应用ref
不要适度应用ref,当产生事件的DOM正好是要操作的DOM元素时能够用event.target的模式
5.4 React中收集表单数据
5.4.1 非受控组件与非受控组件
非受控组件:现用现取(ref)
受控组件:随着输出保护状态为受控组件(onChange , setState)
5.5 组件的 生命周期
5.5.1 成果
需要:定义组件实现以下性能:
让指定的文本做显示 / 暗藏的突变动画
- 从齐全可见,到彻底隐没,耗时2S
- 点击“不活了”按钮从界面中卸载组件
5.5.2. 挂载与卸载
挂载:mount。当 组件第一次被渲染到 DOM 中的时候,就为其设置一个计时器。这在 React 中被称为“挂载(mount)”。
卸载:unmount。同时,当 DOM 中 组件被删除的时候,应该革除计时器。这在 React 中被称为“卸载(unmount)”
5.5.3 了解
- 组件从创立到死亡它会经验一些特定的阶段。
- React组件中蕴含一系列勾子函数(生命周期回调函数), 会在特定的时刻调用。
- 咱们在定义组件时,会在特定的生命周期回调函数中,做特定的工作。
5.5.4 生命周期流程图(旧)
.71zviwretq80.png)
生命周期的三个阶段(旧)
初始化阶段: 由ReactDOM.render()触发---首次渲染
1). constructor()
2). componentWillMount()
3). render()
4). componentDidMount() = = = =>罕用,个别在这个钩子中做一些初始化的事,例如开启定时器、 发送网络申请、订阅音讯、开启监听, 发送ajax申请等
更新阶段: 由组件外部this.setSate()或父组件从新render触发
1). shouldComponentUpdate()
2). componentWillUpdate()
3). render() = = = =>必须要应用
4). componentDidUpdate()
卸载组件: 由ReactDOM.unmountComponentAtNode()触发
1). componentWillUnmount() = = = =>罕用,个别在这个钩子做一些收尾的工作,例如,敞开定时 器、勾销订阅音讯
5.5.5 生命周期流程图(新)
.348vorlsgm80.png)
生命周期的三个阶段(新)
1. 初始化阶段: 由ReactDOM.render()触发---首次渲染
constructor()
<font color=red> getDerivedStateFromProps</font>(新增,很少用,上官网理解即可)
(此办法实用于常见的用例,即 state 的值在任何时候都取决于 props)
render()
componentDidMount()
更新阶段: 由组件外部this.setSate()或父组件从新render触发
<font color=red>getDerivedStateFromProps</font>
shouldComponentUpdate()
render()
<font color=red> getSnapshotBeforeUpdate </font> 在更新之前获取快照,有点实用意义
componentDidUpdate()
3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
componentWillUnmount()
5.5.6 重要勾子和行将废除的勾子
重要勾子
- render:必须要应用,初始化渲染或更新渲染调用
- componentDidMount:个别在这个钩子中做一些初始化的事,例如开启定时器、 发送网络申请、订阅音讯,开启监听, 发送ajax申请等
- componentWillUnmount:做一些收尾工作, 如: 清理定时器,勾销订阅等
行将废除的勾子
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate
16版本能失常应用,17版本应用会呈现正告,下一个大版本须要加上UNSAFE_前缀能力应用,当前可能会被彻底废除,不倡议应用。
5.6 虚构DOM与DOM Diffing算法
- 基本原理图
经典面试题:
1). react/vue中的key有什么作用?(key的外部原理是什么?)
2). 为什么遍历列表时,key最好不要用index?
虚构DOM中key的作用:
1). 简略地说: key是虚构DOM对象的标识, 在更新显示时key起着极其重要的作用。
2). 具体地·说: 当状态中的数据发生变化时,react会依据【新数据】生成【新的虚构DOM】, 随后React进行【新虚构DOM】与【旧虚构DOM】的diff比拟,比拟规定如下:
a. 旧虚构DOM中找到了与新虚构DOM雷同的key:
(1).若虚构DOM中内容没变, 间接应用之前的实在DOM
(2).若虚构DOM中内容变了, 则生成新的实在DOM,随后替换掉页面中之前的实在DOM
b. 旧虚构DOM中未找到与新虚构DOM雷同的key
依据数据创立新的实在DOM,随后渲染到到页面
- 用index作为key可能会引发的问题:
1) 若对数据进行:逆序增加、逆序删除等毁坏程序操作:
会产生没有必要的实在DOM更新 ==> 界面成果没问题, 但效率低。
2.)如果构造中还蕴含输出类的DOM:
会产生谬误DOM更新 ==> 界面有问题。
3) ==留神!==如果不存在对数据的逆序增加、逆序删除等毁坏程序操作, 仅用于渲染列表用于展 示,应用index作为key是没有问题的。
3. 开发中如何抉择key?:
1) 最好应用每条数据的惟一标识作为key, 比方id、手机号、身份证号、学号等惟一值。
2) 如果确定只是简略的展现数据,用index也是能够的。
6 React利用(基于React脚手架)
6.1 应用create-react-app创立react利用
6.1.1 react脚手架
xxx脚手架: 用来帮忙程序员疾速创立一个基于xxx库的模板我的项目
1)蕴含了所有须要的配置(语法查看、jsx编译、devServer…)2) 下载好了所有相干的依赖、
3)能够间接运行一个简略成果
- react提供了一个用于创立react我的项目的脚手架库: create-react-app
- 我的项目的整体技术架构为: react + webpack + es6 + eslint
- 应用脚手架开发的我的项目的特点: 模块化, 组件化, 工程化
6.1.2 创立我的项目并启动
第一步,全局装置:npm i -g create-react-app
第二步,切换到想创我的项目的目录,应用命令:create-react-app hello-react
第三步,进入我的项目文件夹:cd hello-react
第四步,启动我的项目:npm start
6.1.3 react脚手架我的项目构造
public ---- 动态资源文件夹
favicon.icon ------ 网站页签图标(肯定要是icon格局)
<font color=red> index.html -------- 主页面</font>(整个我的项目只有这一个html文件,SPA利用,即单页面利用)
logo192.png ------- logo图
logo512.png ------- logo图
manifest.json ----- 利用加壳的配置文件
robots.txt -------- 爬虫协定文件
src ---- 源码文件夹
App.css -------- App组件的款式
<font color=red>App.js --------- App 组件</font>
App.test.js ---- 用于给App做测试(简直不必)
index.css ------ 款式
<font color=red> index.js ------- 入口文件</font>
logo.svg ------- logo图
reportWebVitals.js
--- 页面性能剖析文件(须要web-vitals库的反对)
setupTests.js
---- 组件单元测试的文件(须要jest-dom库的反对)
6.1.4 性能界面的组件化编码流程(通用)
- 拆分组件: 拆分界面,抽取组件
- 实现动态组件: 应用组件实现动态页面成果
实现动静组件
3.1 动态显示初始化数据
3.1.1 数据类型
3.1.2 数据名称
3.1.3 保留在哪个组件?
3.2 交互(从绑定事件监听开始)
6.2 react ajax
6.2.1 了解
- 留神
- React自身只关注于界面, 并不蕴含发送ajax申请的代码
- 前端利用须要通过ajax申请与后盾进行交互(json数据)
- react利用中须要集成第三方ajax库(或本人封装)
- 罕用的ajax申请库
- Query: 比拟重, 如果须要另外引入不倡议应用
axios: 轻量级, 倡议应用
1) 封装XmlHttpRequest对象的ajax
2) promise格调
3) 能够用在浏览器端和node服务器端
6.2.2 axios
- 文档
- 相干API
GET申请
axios.get('/user?ID=12345') .then(function (response) { console.log(response.data); }) .catch(function (error) { console.log(error); });axios.get('/user', { params: { ID: 12345 } }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });
POST申请
axios.post('/user', { firstName: 'Fred', lastName: 'Flintstone'}).then(function (response) {console.log(response);}).catch(function (error) {console.log(error);});
6.2.3 react脚手架配置代理总结
办法1
在package.json中追加如下配置
"proxy":"http://localhost:5000"
阐明:
1)长处:配置简略,前端申请资源时能够不加任何前缀。
2)毛病:不能配置多个代理。
3)工作形式:上述形式配置代理,当申请了3000不存在的资源时,那么该申请会转发给5000 (优先匹配前端资源)
办法2:
1)第一步:创立代理配置文件
在src下创立配置文件:src/setupProxy.js
2) 编写setupProxy.js配置具体代理规定:
const proxy = require('http-proxy-middleware') module.exports = function(app) { app.use( proxy('/api1', { //api1是须要转发的申请(所有带有/api1前缀的申请都会转发给5000) target: 'http://localhost:5000', //配置转发指标地址(能返回数据的服务器地址) changeOrigin: true, //管制服务器接管到的申请头中host字段的值 /* changeOrigin设置为true时,服务器收到的申请头中的host为:localhost:5000 changeOrigin设置为false时,服务器收到的申请头中的host为:localhost:3000 changeOrigin默认值为false,但咱们个别将changeOrigin值设为true */ pathRewrite: {'^/api1': ''} //去除申请前缀,保障交给后盾服务器的是失常申请地址(必须配置) }), proxy('/api2', { target: 'http://localhost:5001', changeOrigin: true, pathRewrite: {'^/api2': ''} }) ) }
阐明:
- 长处:能够配置多个代理,能够灵便的管制申请是否走代理。
- 毛病:配置繁琐,前端申请资源时必须加前缀。
6.2.4 音讯订阅-公布机制
- 工具库: PubSubJS
- 下载: npm install pubsub-js --save
应用:
1) import PubSub from 'pubsub-js' //引入
2) PubSub.subscribe('delete', function(data){ }); //订阅
3) PubSub.publish('delete', data) //公布音讯
了解
1)先订阅,再公布(了解:有一种隔空对话的感觉)
2)实用于任意组件间通信
3)要在组件的componentWillUnmount中勾销订阅
6.2.5 扩大:Fetch(关注拆散思维)
文档
1) https://github.github.io/fetch/
2) https://segmentfault.com/a/11...
特点
1)fetch: 原生函数,不再应用XmlHttpRequest对象提交ajax申请(axios和jQuery都是对XmlHttpRequset的封装)
2)老版本浏览器可能不反对
相干API
1)GET申请
fetch(url).then(function(response) { return response.json() }).then(function(data) { console.log(data) }).catch(function(e) { console.log(e) });
2)POST申请
fetch(url, { method: "POST", body: JSON.stringify(data), }).then(function(data) { console.log(data) }).catch(function(e) { console.log(e) })
7 React路由
7.1 相干了解
7.1.1 SPA 的了解
- 单页Web利用(single page web application,SPA)。
- 整个利用只有==一个残缺的页面==。
- 点击页面中的链接==不会刷新==页面,只会做页面的==部分更新。==
- 数据都须要通过ajax申请获取, 并在前端异步展示。
7.1.2 路由的了解
1. 什么是路由?
- 一个路由就是一个映射关系(key:value)
- key为门路, value可能是function或component
2. 路由分类
1) 后端路由:
- 了解: value是function, 用来解决客户端提交的申请。
- 注册路由: router.get(path, function(req, res))
- 工作过程:当node接管到一个申请时, 依据申请门路找到匹配的路由, 调用路由中的函数来解决申请, 返回响应数据
2) 前端路由:
- 浏览器端路由,value是component,用于展现页面内容。
- 注册路由: <Route path="/test" component={Test}>
- 工作过程:当浏览器的path变为/test时, 以后路由组件就会变为Test组件
7.1 .3 react-router-dom的了解
- react的一个插件库。
- 专门用来实现一个SPA利用。
- 基于react的我的项目根本都会用到此库。
7.2 react-router-dom相干API
7.2.1 内置组件
- <BrowserRouter>
- <HashRouter>
- <Route>
- <Redirect>
- <Link>
- <NavLink>
- <Switch>
7.2.2. 其它
- history对象
- match对象
- withRouter函数
[TOC]
1. setState
setState更新状态的2中写法
setState(stateChange, [callback])------对象式的setState
stateChange为状态扭转对象(该对象能够体现出状态的更改)
this.setState({count:count+1})
- callback是可选的回调函数, 它在状态更新结束、界面也更新后(render调用后)才被调用
setState(updater,[callback] ------函数式的setState
this.setState((state,props) => { return {count:state.count+1} // return {count:props.x+1} })
- updater为返回stateChange对象的==函数==
- updater能够接管到state和props
- callback是可选的回调函数, 它在状态更新结束、界面也更新后(render调用后)才被调用
总结:
1)对象式的setState式函数式setState的简写形式(语法糖)
2)应用准则:(仅倡议,非相对)
- 如果新状态不依赖于原状态 ===> 应用对象形式
- 如果新状态依赖于原状态 ===> 应用函数形式
- 如果须要在setState() 执行后获取最新的状态数据,要在第二个callback函数中读取
- 备注:setState是同步办法,然而setState引起的React的更新的动作是异步执行,如果须要在setState() 执行后获取最新的状态数据,要在第二个callback函数中读取
2 lazyLoad
路由组件的lazyLoad:避免资源一次性加载过多,让用户能够按需加载
//1.通过React的lazy函数配合import()函数动静加载路由组件 ===> 路由组件代码会被离开打包 const Login = lazy(()=>import('@/pages/Login')) //2.通过<Suspense>指定在加载失去路由打包文件前显示一个自定义loading界面 <Suspense fallback={<h1>loading.....</h1>}> <Switch> <Route path="/xxx" component={Xxxx}/> <Redirect to="/login"/> </Switch> </Suspense>
3 Hooks
3.1 React Hook / Hook是什么?
- Hooks是React 16.8.0 版本减少的新个性/新语法
能够让你在==函数组件==中应用state以及其余React个性
- 函数式组件:用函数定义的组件,实用于简略组件的定义(没有实例,this=undefined)不能用 state,refs
3.2 三个罕用的Hook
- State Hook : React.useState()
- Effect Hook:React.useEffect()
- Ref Hook:React.useRef()
3.3 State Hook
- State Hook让函数组件也能够有state状态,并进行状态数据的读写操作
- 语法:const [xxx, setXxx] = React.useState(initValue)
userState()阐明
参数:第一次初始化指定的值在外部做缓存
返回值:蕴含两个元素的数组,第1个位外部以后状态值,第2个位更新状态值的函数
setXxx() 2种写法:
setXxx(newValue):参数为非函数值,间接指定新的状态值,外部用其笼罩原来的状态值
setXxx(value => newValue):参数为函数,接管原来的状态值,返回新的状态值,外部用其笼罩原来的状态值
3.4 Effect Hook
- Effect Hook 能够让你在函数组件种执行副作用操作(用于模仿类组件中的生命周期钩子)
React中副作用操作:
发Ajax申请数据
设置订阅/启动定时器
手动更改实在DOM
语法和阐明
useEffect (() =>{//在此能够执行任何带副作用操作return () =>{//在组件卸载前执行,在此做一些收尾工作,比方革除定时器/勾销订阅等}},[stateValue]) //如果指定的是[],回调函数只会在第一次render()后执行,之后只检测stateValue
React.useEffect(() => { let timer= setInterval(() => { //设置定时器,相当于componentDidMount(),(componentDidUpdate()) setCount(count => count+1) },1000) return () => { clearInterval(timer) //componentWillUnmount() } },[]) //不写[],检测所有人
能够把useEffect Hook看作是三个函数的组合
componentDidMount()
componentDidUpdate()
componentWillUnmount()
3.5 Ref Hook
- Ref Hook能够在函数组件中存储/查找组件内的标签或任意其余数据
语法:
const refContainer = useRef()
- 作用:保留标签对象,性能与React.createRef() 一样
4 Fragment
应用
<Fragment><Fragment><></>
作用
能够不必必须有一个实在的DOM根标签了,fragment会在解析是去掉,【为了骗过jsx】
5 Context
- 了解: 一种组件间通信的形式,罕用于【祖组件】和【后辈组件】
应用:
1)创立Context容器对象
const XxxContext = React.createContecxt()
2) 渲染子组件时,里面包裹xxxContext.Provider,通过value属性给后辈组件传递数据
<xxxContext.Provider value={数据}> 子组件</xxxContext.Provider>
3) 后辈组件读取数据
//第一种形式:仅实用于类组件static contextType = xxxContext //申明接管contextthis.context //读取context中的value数据//第二种形式:函数组件与类组件都能够<xxxContext.Consumer> { value => { //value 就是 context中value数据 要显示的内容}}</xxxContext.Consumer>
- 留神:在利用开发中个别不必context,个别都用它来封装react插件
6 组件优化
Component的两个问题
1)只有执行setState(),即便不扭转状态数据,组件也会从新render() ==>效率低
2)只有以后组件从新render(),就会从新render子组件,纵使子组件没有用到父组件的任何数据 ==>效率低
提高效率的做法
只有当组件的state或者props数据发生变化时才从新render()
起因
Component 中的shouldComponentUpdate()总是返回true
解决办法:
1)办法1:
- 重写shouldComponentUpdate()办法,比拟新旧state或props数据,有变动才返回true,否则返回false
2)办法2:
应用PureComponent
PureComponent重写了shouldComponentUpdate(), 只有state或props数据有变动才返回true
留神:
只是进行state和props数据的浅比拟,如果只是数据对象外部数据变了,返回false
不要间接批改state数据,而是要产生新数据
3)我的项目中个别应用办法2来进行优化
7 render props
如何向组件外部动静传入带内容的构造(标签)?
1)vue中:应用slot技术。也就是通过组件标签体传入构造 <B/>
2)React 中:
- 应用children props:通过组件标签体传入构造
- 应用render props:通过组件标签属性传入构造,而且能够携带数据,个别用render函数属性
children props
<A> <B>xxxx</B></A>{this.props.children}问题: 如果B组件须要A组件内的数据, ==> 做不到
render props
<A render={(data) => <C data={data}></C>}></A>A组件: {this.props.render(外部state数据)}C组件: 读取A组件传入的数据显示 {this.props.data}
8 谬误边界
了解:
谬误边界(Error boundary):用来捕捉==后辈==组件谬误,渲染出备用页面
应用于生产环境
特点
只能捕捉后辈组件==生命周期==产生的谬误,不能捕捉本人组件产生的谬误和其余组件在合成事件、定时器中产生的谬误
应用形式:
getDerivedStateFromError配合componentDidCatch
// 生命周期函数,一旦后盾组件报错,就会触发static getDerivedStateFromError(error) { console.log(error); // 在render之前触发 // 返回新的state return { hasError: true, };}componentDidCatch(error, info) { // 统计页面的谬误。发送申请发送到后盾去 console.log(error, info);}
9 组件通信形式总结
9.1 组件间的关系
- 父子关系
- 兄弟关系(非嵌套组件)
- 祖孙组件(跨级组件)
9.2 几种通信形式:
props:
- children props
- render props
音讯订阅——公布
pubs -sub、event等等
集中管理
redux、dav等等
ConText:
生产者——消费者模式
9.3 比拟好的搭配形式
- 父子组件:props
- 兄弟组件:音讯订阅——公布、集中管理
- 祖孙组件(跨级组件):音讯订阅——公布、集中式治理、conText(开发用得少,封装插件用得多)