共计 17215 个字符,预计需要花费 44 分钟才能阅读完成。
基于 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 // 申明接管 context this.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(开发用得少,封装插件用得多)