0.链接
状态码精选 https://www.cnblogs.com/yaya-003/p/12653602.html
ts精选 https://blog.csdn.net/xgangzai/article/details/119012373?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-1.pc_relevant_paycolumn_v3&spm=1001.2101.3001.4242.2&utm_relevant_index=4
1.响应式布局有几种方法
响应式布局方法一:媒体查询
使用@media媒体查询可以针对不同的媒体类型定义不同的样式,特别是响应式页面,可以针对不同屏幕的大小,编写多套样式,从而达到自适应的效果。举例来说:
通过媒体查询,可以通过给不同分辨率的设备编写不同的样式来实现响应式的布局,比如我们为不同分辨率的屏幕,设置不同的背景图片。比如给小屏幕手机设置@2x图,为大屏幕手机设置@3x图,通过媒体查询就能很方便的实现。
但是媒体查询的缺点也很明显,如果在浏览器大小改变时,需要改变的样式太多,那么多套样式代码会很繁琐。
响应式布局方法二:百分比%
比如当浏览器的宽度或者高度发生变化时,通过百分比单位,通过百分比单位可以使得浏览器中的组件的宽和高随着浏览器的变化而变化,从而实现响应式的效果。
height,width属性的百分比依托于父标签的宽高。但是,padding、border、margin等属性的情况又不一样
子元素的padding如果设置百分比,不论是垂直方向或者是水平方向,都相对于直接父亲元素的width,而与父元素的height无关。
子元素的margin如果设置成百分比,不论是垂直方向还是水平方向,都相对于直接父元素的width
border-radius不一样,如果设置border-radius为百分比,则是相对于自身的宽度
缺点
计算困难,如果我们要定义一个元素的宽度和高度,按照设计稿,必须换算成百分比单位。
各个属性中如果使用百分比,相对父元素的属性并不是唯一的。比如width和height相对于父元素的width和height,而margin、padding不管垂直还是水平方向都相对比父元素的宽度、border-radius则是相对于元素自身等等,造成我们使用百分比单位容易使布局问题变得复杂。
所以,不建议用%来做响应式布局。
响应式布局方法三:vw/vh
css3中引入了一个新的单位vw/vh,与视图窗口有关,vw表示相对于视图窗口的宽度,vh表示相对于视图窗口高度。 任意层级元素,在使用vw单位的情况下,1vw都等于视图宽度的百分之一。
与百分比布局很相似,但更好用。
响应式布局方法四:rem
rem单位是相对于字体大小的html元素,也称为根元素。 默认情况下,html元素的font-size为16px。所以此时1rem = 16px。
优化版
//动态为根元素设置字体大小
functioninit () {
// 获取屏幕宽度
varwidth = document.documentElement.clientWidth
// 设置根元素字体大小。此时为宽的10等分
document.documentElement.style.fontSize = width / 10 + 'px'
}
//首次加载应用,设置一次
init()
// 监听手机旋转的事件的时机,重新设置
window.addEventListener('orientationchange', init)
// 监听手机窗口变化,重新设置
window.addEventListener('resize', init)
理解:上面代码实现了,无论设备可视窗口如何变化,始终设置rem为width的1/10.即实现了百分比布局。就没有第一版的媒体查询那样僵硬。
以上代码需在dom之前写入(可放在head里面第一个script标签)
响应式布局方法五:flex弹性布局
弹性布局是一种十分方便的,只需要依赖于CSS样式的实现响应式布局的方式,也是最多用到的一种实现响应式的方法。
尤其是现在类似于某宝、某东一类的电商web站或者手机app的页面,利用弹性布局是都可以很轻松的实现的。
弹性布局在父、子元素上都有相对应的属性来规范子元素在父元素中的“弹力”。
在父元素上,我们经常会用到的有关弹性布局的属性主要有 flex-direction主轴方向 , flex-wrap项目都排在一条线(又称”轴线”)上。flex-wrap属性定义,如果一条轴线排不下,如何换行 , justify-content主轴上的对齐方式 , align-items交叉轴上如何对齐 , align-content 多根轴线的对齐方式,这几个属性分别从 主轴的方向、是否换行、项目在主轴上的对齐方式、项目在交叉轴上的对齐方式、项目在多根轴线上的对齐方式来规范了项目在父元素中的弹性。
在子元素上,我们经常会用到的有关弹性布局的属性主要有 order , flex-grow , flex-shrink ,flex-basis , align-self ,这几个属性分别从 项目的排序、项目放大比例、项目缩小比例、项目占据主轴空间、单个项目在交叉轴上的对齐方式来规范了项目自身的弹性。
2.如何让一个元素水平/垂直居中
(1)flex布局。
.father {
width: 200px;
height: 200px;
border: 1px solid red;
display: flex;
justify-content: center;
align-items: center;
}
(2)grid布局。
.father {
width: 200px;
height: 200px;
border: 1px solid red;
display: grid;
place-items: center;
}
(3)定位。
.father {
width: 200px;
height: 200px;
border: 1px solid red;
position: relative;
}
.son {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
(4)对于文本。
.father {
width: 200px;
height: 200px;
border: 1px solid red;
text-align: center;
line-height: 200px;
(5) table布局。
.father {
width: 200px;
height: 200px;
border: 1px solid red;
display: table;
}
.son {
display: table-cell;
vertical-align: middle;
text-align: center;
}
3.CSS盒子模型
CSS盒子模型就是在CSS技术所使用的一种思维模型。CSS假定所有的HTML文档元素都生成一个描述该元素在HTML文档布局中所占空间的矩形元素框,可以形象地将其看作是一个盒子。通过定义一系列与盒子相关的属性,可极大地丰富和促进各个盒子乃至整个HTML文档的表现效果和布局结构。
CSS盒子模型由内容区、填充、边框和空白边四部分组成。内容区是盒子模型的中心,呈现盒子的主要信息内容;填充是内容区和边框之间的空间;边框是环绕内容区和填充的边界;空白边位于盒子的最外围,是添加在边框外周围的空间。
1、丰富的样式定义:CSS提供了丰富的文档样式外观,以及设置文本和背景属性的能力;允许为任何元素创建边框,以及元素边框与其他元素间的距离,以及元素边框与元素内容间的距离;允许随意改变文本的大小写方式、修饰方式以及其他页面效果。
2、易于使用和修改:CSS可以将样式定义在HTML元素的style属性中,也可以将其定义在HTML文档的header部分,也可以将样式声明在一个专门的CSS文件中,以供HTML页面引用。总之,CSS样式表可以将所有的样式声明统一存放,进行统一管理。
4.div 和 p
div元素是块级的(简单地说,它等同于其前后有断行),用于组合一大块的代码。
p(段落)元素是块级的,前后断行,而且还要再隔一行.相当于断两行。
5.解决本地开发接口请求跨域问题3种方案
1.webpack-dev-server配置跨域方案
如果你项目是用webpack作为前端自动化构建工具的话,那么可以引用webpack-dev-server来进行配置跨域方案。webpack-dev-server是一个小型的nodejs服务器,是基于express框架的,用于实时监听和打包编译静态资源。其中里面有一个属性是proxy,是专门来配置代理请求接口的。
举个例子:
比如我现在通过webpack构建了一个本地开发环境,端口号是9000,现在我要在本地去请求(GET)http://jsonplaceholder.typicode.com/users地址获取数据,如果前端没有设置代理的话,请求会因为跨域请求失败。这时候通过如下配置,就可以正常请求了。
devServer: {
contentBase: __dirname + "/",
port: 9000,
proxy: {
"/users": {//需要代理的路径target: "http://jsonplaceholder.typicode.com",//需要代理的域名changeOrigin:true//必须配置为true,才能正确代理}
}
}
通过如上配置,然后在js里面这样请求就可以成功拿到数据了:
//使用fetch获取ajax请求fetch('/users')//填写路径即可.then(function(response) {returnresponse.json()
}).then(function(json) {
console.log('parsed json', json)
}).catch(function(ex) {
console.log('parsing failed', ex)
})
这是通过webpack-dev-server配置的代理方案,那如果没有webpack-dev-server服务,要如何配置代理方案呢?比如在gulp和fis环境中,要怎么设置nodejs的代理服务。这时候我们就得来追寻下webpack-dev-server代理的实现机制了。
2.让新版Chrome支持本地跨域请求调试
提示无法进行跨域请求。这时候如果解决呢?其实可以通过Chrome的启动参数,来解决这个问题,让我们的本地联调测试更加方便。具体方法是:
1、创建一个Chrome的启动快捷方式;
2、右键点击快捷方式属性,然后在目标路径后面,添加以下参数:
–disable-web-security –user-data-dir=”e:\chromedev“
注意在最新版本的Chrome中,–user-data-dir参数也是必须要添加的,下划线部分可以随便指定到其他路径,这里保存是的Chrome的用户数据的。
3.nginx反向代理解决跨域设置
1、打开本地Host文件, C:\Windows\System32\drivers\etc\ hosts文件
配置本地域名:
127.0.0.1 qyh.xxx.com //目的是浏览器访问使用域名 ,如果不懂就安装配置就可以
2、打开安装nginx配置文件 进行配置
server {
listen 80 default backlog=2048;
listen 443 ssl;
server_name qyh.citic.com;#这里的域名要跟HOST配置一致
#ssl on;
ssl_certificate d:/nginx-1.11.10/conf/server.crt;#HTTPS需要证书路径
ssl_certificate_key d:/nginx-1.11.10/conf/server.key;#HTTPS需要证书路径
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4:HIGH:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!AESGCM;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:100m;
ssl_session_timeout 100m;
location /{
root D:/xampp/htdocs;#默认请求路径
}
autoindex on;
index index.html index.htm index.shtml;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
location /apis {
rewrite ^.+apis/?(.*)$ /$1 break;
include uwsgi_params;
proxy_pass https://qyhtest.citic.com/;#代理地址 --服务器接口域名
}
}
注意: server_name 要与HOST域名一致。
proxy_pass 是代理接口域名
listen监听443 及80端口处。
6. var, let, const
1. 块级作用域 let, const
ES5 中作用域有:全局作用域、函数作用域。没有块作用域的概念。
ES6 中新增了块级作用域。块作用域由 { } 包括,if语句和 for语句里面的{ }也属于块作用域。
2. var、let、const的区别
var定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问。可以变量提升。
let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。不可以变量提升。
const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改。
7. json,字符集 编码, dom和bom, 原型和原型链
json通用数据结构,用来数据交换,可以表示数组,对象,string,number,一般ajax,request请求对象化回来的就是json
unicode字符集utf-8编码
dom是文档对象模型 document.getElementById(),bom浏览器对象模型核心是window
dom方法返回的和arguments这些类数组可以通过 array,prototype.slice.call或者array.form
使用构造函数来新建一个对象的,每一个对象都有一个prototype属性,属性值是一个对象,当访问一个对象时,如果这个对象内部不存在这个属性,那么它会去原型对象里找这个属性,这个原型对象又会有自己的原型,于是这么一直找下去,就是原型链的概念。
在JavaScript 中,每个对象都有一个指向它的原型(prototype)对象的内部链接。这个原型对象又有自己的原型,直到某个对象的原型为 null 为止(也就是不再有原型指向),组成这条链的最后一环。这种一级一级的链结构就称为原型链(prototype chain)。
8.异步编程
1.回调函数
使用回调函数是最常见的一种形式
//jQuery ajax$.get('test.php',res=>{//数据处理});//node异步读取文件letfs=require('fs'); fs.read('file/path',(error,data)=>{//数据处理});
回调函数就是定义函数的时候,将另外一个函数(回调函数)作为参数传入,在异步操作执行完成后就会执行该回调函数,从而可以保证在回调函数中的操作可以在异步执行完成之后执行。回调函数的缺点是当需要执行多个异步操作时,需要将多个回调函数嵌套在一起,组成代码结构上的混乱,可读性较差,被称为“回调地狱”。
func1(data1,()=>{ func2(data2,()=>{ func3(data3,()=>{ //业务逻辑 });});});
2.Promise
Promise以一种链式调用的方法来组织异步代码,可以将原来以回调函数形式调用的异步操作,改写为promise链式调用
//jQuery ajax promise$('test.html').then(res=>{//业务逻辑}).then(res=>{//业务逻辑});
我们还可以利用ES6的Promise构造函数,自定义Promise
letresultA=newPromise((resolve,reject)=>{letflag=Math.random()<0.5;setTimeout(()=>{if(flag){resolve({result:true,msg:'ok'}); }else{reject({result:false,msg:'error'}); } },0); }); resultA.then(res=>{console.log(res.msg);returnPromise.resolve('I am from this first promise'); }).catch(err=>{console.log(err.msg); }).then(res=>{console.log(res); });
在最新版本的node(node 8.0+)环境里,还可以利用util.promisify方法将回调函数形式的函数直接转换为Promise形式。
letutil =require('util');letfs =require('fs');letreadFilePromise = util.promisify(fs.readFile);readFilePromise('demo.js','utf-8').then((data)=>{console.log(data); });
3.Async/Await
node7.6以上的版本引入了一个es7的新特性 Async/Await,专门用来进行异步控制,下面先看一简单的个例子
letdelay =newPromise((resolve,reject)=>{setTimeout(()=>{console.log('test');resolve('msg from promise'); });});letbaz=async()=>{letres =awaitdelay;console.log(res);//'msg from promise'};baz();
首先我们需要使用async关键字定义一个包含异步代码执行的函数,在promise形式你的异步执行函数前面使用await关键字,就可以将异步写成同步的操作形式。
相比Generators生成器,由于Async/Await使原生的异步控制方案,所以比较推荐使用的。
4.Generators
node的著名开发者TJ利用ES6的新特性生成器开发了一个异步控制控制工具co,Generators生成器,借助co可以将异步代码的写法写成类似同步代码的形式。
letutil =require('util');letfs =require('fs');letco=require('co');letreadFilePromise = util.promisify(fs.readFile);co(function*(){letbaz =yieldreadFilePromise('baz.js','utf-8');console.log(baz);letfoo =yieldreadFilePromise('foo.js','utf-8');console.log(foo);});
可以看出Generator的优点显而易见,它可以使异步代码写的非常清晰,可读性很高,缺点使依赖第三方库才能使用该特性。
9. Promise 解决了什么问题
回调地狱
10.JS中 并发(concurrency)和并行(parallelism)区别
1.并发:宏观概念,有两个任务A和B,在一段时间内,通过在A和B两个任务间切换,来完成两个任务,这种情况叫并发
2.并行:微观概念,假设CPU有两个核心,那么我们就可以同时完成A,B两个任务。即:同时完成多个任务的情况可以称为并行。
11. mvvm,mvc区别
model,view都有
Controller 层会接收用户所有的操作,并根据写好的代码进行相应的操作——触发 Model 层,或者触发 View 层,抑或是两者都触发。
缺点就是 Controller 层和 View 层之间是一一对应的,断绝了 View 层复用的可能,因而产生了很多冗余代码,代码集中在Controller压力很大,Zepto,juqery,angular
mvvm双向绑定,react,vue
12.react生命周期
Constructor
1: 用于初始化操作,一般很少使用
2:唯一一个直接修改state的地方,其他地方通过调用this.setState()方法。
getDerivedStateFromProps
1:当state需要从props初始化时,使用
2:尽量不使用,维护俩者状态需要消耗额外资源,增加复杂度
3:每次render都会调用
4:典型场景表单获取默认值
componentDidMount
1:UI渲染完成后调用
2:只执行一次
3:典型场景:获取外部资源
componentWillUnmount
1:组件被移除时调用
2:典型场景:资源释放
getSnapshotBeforeUpdate
1:在render之前调用,state已更新
2:典型场景:获取render之前的dom状态
componentDidUpdate
1:每次UI更新被调用
2:典型场景:页面通过props重新获取数据
shouldComponentUpdate
1:觉得Vistual Dom是否重绘
2:一般可以由PuerComponent自动实现
3:典型场景:性能优化
13.immer 简介
immer 的作者同时也是 mobx 的作者。mobx 又像是把 Vue 的一套东西融合进了 React,已经在社区取得了不错的反响。immer 则是他在 immutable 方面所做的另一个实践。比lodash的深拷贝好体积只有五分之一。
与 immutable-js 最大的不同,immer 是使用原生数据结构的 API 而不是像 immutable-js 那样转化为内置对象之后使用内置的 API,举个简单例子:
const produce= require('immer')
const state= {
done: false,
val: 'string',
}
// 所有具有副作用的操作,都可以放入 produce 函数的第二个参数内进行
// 最终返回的结果并不影响原来的数据
const newState= produce(state, (draft) => {
draft.done= true
})
console.log(state.done) // false
console.log(newState.done) // true
通过上面的例子我们能发现,所有具有副作用的逻辑都可以放进 produce 的第二个参数的函数内部进行处理。在这个函数内部对原来的数据进行任何操作,都不会对原对象产生任何影响。
这里我们可以在函数中进行任何操作,例如 push splice 等非 immutable 的 API,最终结果与原来的数据互不影响。
Immer 最大的好处就在这里,我们的学习没有太多成本,因为它的 API 很少,无非就是把我们之前的操作放置到 produce 函数的第二参数函数中去执行。
immer 原理解析
Immer 源码中,使用了一个 ES6 的新特性 Proxy 对象。Proxy 对象允许拦截某些操作并实现自定义行为,但大多数 JS 同学在日常业务中可能并不经常使用这种元编程模式,所以这里简单且快速的介绍一下它的使用。
Proxy
Proxy 对象接受两个参数,第一个参数是需要操作的对象,第二个参数是设置对应拦截的属性,这里的属性同样也支持 get,set 等等,也就是劫持了对应元素的读和写,能够在其中进行一些操作,最终返回一个 Proxy 对象实例。
constproxy=newProxy({},{get(target,key){// 这里的 target 就是 Proxy 的第一个参数对象console.log('proxy get key',key)},set(target,key,value){console.log('value',value)}})// 所有读取操作都被转发到了 get 方法内部proxy.info// 'proxy get key info'// 所有设置操作都被转发到了 set 方法内部proxy.info=1// 'value 1'
上面这个例子中传入的第一个参数是一个空对象,当然我们可以用其他已有内容的对象代替它,也就是函数参数中的 target。
immer 中的proxy
immer 的做法就是维护一份 state 在内部,劫持所有操作,内部来判断是否有变化从而最终决定如何返回。下面这个例子就是一个构造函数,如果将它的实例传入 Proxy 对象作为第一个参数,就能够后面的处理对象中使用其中的方法:
classStore{constructor(state){this.modified=falsethis.source=statethis.copy=null}get(key){if(!this.modified)returnthis.source[key]returnthis.copy[key]}set(key,value){if(!this.modified)this.modifing()returnthis.copy[key]=value}modifing(){if(this.modified)returnthis.modified=true// 这里使用原生的 API 实现一层 immutable,// 数组使用 slice 则会创建一个新数组。对象则使用解构this.copy=Array.isArray(this.source)?this.source.slice():{...this.source}}}
上面这个 Store 构造函数相比源代码省略了很多判断的部分。实例上面有 modified,source,copy 三个属性,有 get,set,modifing 三个方法。modified 作为内置的 flag,判断如何进行设置和返回。
里面最关键的就应该是 modifing 这个函数,如果触发了 setter 并且之前没有改动过的话,就会手动将 modified 这个 flag 设置为 true,并且手动通过原生的 API 实现一层 immutable。
对于 Proxy 的第二个参数,在简版的实现中,我们只是简单做一层转发,任何对元素的读取和写入都转发到 store 实例内部方法去处理。
constPROXY_FLAG='@@SYMBOL_PROXY_FLAG'consthandler={get(target,key){// 如果遇到了这个 flag 我们直接返回我们操作的 targetif(key===PROXY_FLAG)returntargetreturntarget.get(key)},set(target,key,value){returntarget.set(key,value)},}
这里在 getter 里面加一个 flag 的目的就在于将来从 proxy 对象中获取 store 实例更加方便。
最终我们能够完成这个 produce 函数,创建 store 实例后创建 proxy 实例。然后将创建的 proxy 实例传入第二个函数中去。这样无论在内部做怎样有副作用的事情,最终都会在 store 实例内部将它解决。最终得到了修改之后的 proxy 对象,而 proxy 对象内部已经维护了两份 state ,通过判断 modified 的值来确定究竟返回哪一份。
functionproduce(state,producer){conststore=newStore(state)constproxy=newProxy(store,handler)// 执行我们传入的 producer 函数,我们实际操作的都是 proxy 实例,所有有副作用的操作都会在 proxy 内部进行判断,是否最终要对 store 进行改动。producer(proxy)// 处理完成之后,通过 flag 拿到 store 实例constnewState=proxy[PROXY_FLAG]if(newState.modified)returnnewState.copyreturnnewState.source}
这样,一个分割成 Store 构造函数,handler 处理对象和 produce 处理 state 这三个模块的最简版就完成了,将它们组合起来就是一个最最最 tiny 版的 immer ,里面去除了很多不必要的校验和冗余的变量。但真正的 immer 内部也有其他的功能,例如上面提到的深层嵌套对象的结构化共享等等。
当然,Proxy 作为一个新的 API,并不是所有环境都支持,Proxy 也无法 polyfill,所以 immer 在不支持 Proxy 的环境中,使用 Object.defineProperty 来进行一个兼容。
性能
我们用一个简单测试来测试一下 immer 在实际中的性能。这个测试使用一个具有 100k 状态的状态树,我们记录了一下操作 10k 个数据的时间来进行对比。
freeze 表示状态树在生成之后就被冻结不可继续操作。对于普通 JS 对象,我们可以使用 Object.freeze 来冻结我们生成的状态树对象,当然像 immer / immutable-js 内部自己有冻结的方法和逻辑。
14.react相关
1.setState异步还是同步
通常异步,setTimeout是同步的
componentDidUpdate(nextProps, nextState) {
if (nextState.activateLightColorForRed) {
// when the state is updated (turned red),
// a timeout is triggered to switch it back off
this.turnOffRedTimeout= setTimeout(() => {
this.setState(() => ({activateLightColorForRed: false})
}, 500);
}
}
componentWillUnmount() {
// we set the timeout to this.turnOffRedTimeout so that we can
// clean it up when the component is unmounted.
// otherwise you could get your app trying to modify the state on an
// unmounted component, which will throw an error
clearTimeout(this.turnOffRedTimeout);
}
2.react hook性能优化使用memo、useCallback、useMemo,以及其它钩子作用
https://www.cnblogs.com/seemoon/p/12792987.html
import React, { memo, useCallback, useMemo, useState } from 'react';
// 子组件
const ChildComp = (props) => {
console.log('ChildComp...');
return (<div>ChildComp...</div>);
};
const MemoChildComp = memo(ChildComp);
// 父组件
const Parent = () => {
const [count, setCount] = useState(0);
const [name] = useState('jack');
const [age] = useState(11);
const info = useMemo(() => ({ name, age }), [name, age]);
const changeName = useCallback(() => {
console.log('输出名称...');
}, []);
return (
<div className="App">
<div>hello world {count}</div>
<div onClick={() => { setCount(count => count + 1); }}>点击增加</div>
<MemoChildComp info={info} changeName={changeName}/>
</div>
);
};
export default Parent;
useContext: 获取 context 对象
useReducer: 类似于 Redux 思想的实现但其并不足以替代 Redux可以理解成一个组件内部的 redux:
并不是持久化存储会随着组件被销毁而销毁
属于组件内部各个组件是相互隔离的单纯用它并无法共享数据
配合useContext`的全局性可以完成一个轻量级的 Redux(easy-peasy)
useCallback: 缓存回调函数避免传入的回调每次都是新的函数实例而导致依赖组件重新渲染具有性能优化的效果
useMemo: 用于缓存传入的 props避免依赖的组件每次都重新渲染
useRef: 获取组件的真实节点
useLayoutEffect:DOM更新同步钩子。用法与useEffect类似只是区别于执行时间点的不同
useEffect:属于异步执行并不会等待 DOM 真正渲染后执行而useLayoutEffect则会真正渲染后才触发
可以获取更新后的 state
3.diff算法?
把树形结构按照层级分解只比较同级元素。
时间复杂度O(n)
给列表结构的每个单元添加唯一的key属性方便比较。
React 只会匹配相同 class 的 component这里面的class指的是组件的名字
合并操作调用 component 的 setState 方法的时候, React 将其标记为 - dirty.到每一个事件循环结束, React 检查所有标记 dirty的 component重新绘制.
选择性子树渲染。开发人员可以重写shouldComponentUpdate提高diff的性能
2. React Diff算法 => O(n) => 简单粗暴,所有的节点按层级比较,只会遍历一次
# 按叶子节点位置比较
[0,0] : pA => lA #相同,不理会
[0.0,0.0] : pD => lB #不同,删除pD,添加lB
[0.1,0.1] : pB => lD #不同,删除pB,添加lD
[0.1.0,0.1.0] : pC => Null #last树没有该节点,直接删除pC
[0.1.2,0.1.2] : Null => lC #prev树没有该节点,添加lC到该位置
4.react性能优化方案
重写shouldComponentUpdate来避免不必要的dom操作
使用 production 版本的react.js
使用key来帮助React识别列表中所有子组件的最小变化
5. React与this指向
class App extends React.Component{
constructor(){
this.name
}
handleClick(event){
console.log(this); // 'this' 值为 undefined
}
render(){
return (
<button onClick={this.handleClick}>
Click Me
</button>
);
}
}
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
模拟Render渲染函数生成的虚拟dom产物
renderDom() {
var btn = document.createElement("button");
var t = document.createTextNode("Click Me");
btn.appendChild(t);
function createCallback(fn) {
constcontext=undefined;
return()=>fn.apply(context);//this没有指向实例的原因
//由于react执行回调的时候使用apply方法,指定的上下文是context对象而不是对象实例。
}
btn.addEventListener("click", createCallback(this.handleClick));
document.getElementById("root").appendChild(btn);
return
}
解法1:构造函数上bind
在构造函数上将所有方法讲this绑定到app实例上
constructor(props){super(props);// 绑定实例this.handleClick=this.handleClick.bind(this)}
解法2:render函数上bind
第二种思路和第一种类似只不过是在render函数上bind。
render(){return(<buttononClick={this.handleClick.bind(this)}>Click Me</button>);}
解法3: handle函数使用箭头函数
另外一种思路就是利用箭头函数和词法作用域。
handleClick=(event)=>{// debuggerconsole.log("click",this);// 'this' 值为 undefined}
方法4: 绑定事件函数使用箭头函数
最后一种和上面类似还是利用箭头函数只是位置改为JSX中
render(){return(<buttononClick={()=>this.handleClick}>Click Me</button>);}
5.REACT 版本更新
react16.3
为旧的生命周期添加新的getDerivedStateFromProps()生命周期和UNSAFE_别名。(@bvaughn在#12028中)
添加新的getSnapshotBeforeUpdate()生命周期。(@bvaughn在#12404中)
react16.8.0(2019 年 2 月 6 日)
添加Hooks——一种无需编写类即可使用状态和其他 React 特性的方法。(@acdlite等人在#13968中)
改进useReducerHook 延迟初始化 API。(@acdlite在#14723中)
6.react !!0
如果不使用 !!b 进行强转数据类型会在页面里面输出 0。
render(){constb=0;return<div>{!!b&&<div>这是一段文本</div>}</div>}
15.图片懒加载
https://blog.csdn.net/w1418899532/article/details/90515969
16.HTTP状态码共分为5种类型:
1**信息,服务器收到请求,需要请求者继续执行操作
2**成功,操作被成功接收并处理
3**重定向,需要进一步的操作以完成请求
4**客户端错误,请求包含语法错误或无法完成请求
5**服务器错误,服务器在处理请求的过程中发生了错误
.最常见的状态码:
100Continue继续。客户端应继续其请求
200 - 请求成功
203Non-Authoritative Information非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本
301 - 资源(网页等)被永久转移到其它URL
302Found临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URL
400Bad Request客户端请求的语法错误,服务器无法理解
401Unauthorized请求要求用户的身份认证
404 - 请求的资源(网页等)不存在
405Method Not Allowed客户端请求中的方法被禁止 postget写错了可能是
500 - 内部服务器错误
502Bad Gateway作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应