(reactJS)关于事件处理函数this指向的 props与state,setState方法 合成事件与事件对象 严格模式标签 组件声明周期 纯组件以及性能优化以及关于网络请求 1.关于事件处理函数this指向 2.关于合成事件与事件对象 3.props与state,setState方法 4.关于react框架的严格模式标签 5.关于react组件生命周期 6.关于纯组件与性能优化 7.关于网络请求
1.关于事件处理函数this指向
注意:react框架中绑定给事件的处理函数中,this 指向是不确定的。
想要让事件处理函数中的 this 指向实例,有以下三种解决方案1. 事件处理函数用箭头函数的形式定义函数名 = ( ) => { } (这样定义的事件处理函数其 this 指向定义时所在的上下文,也就是组件实例)2. 在事件处理函数在绑定时套上一层箭头函数< tag onClick= { ( ) => { this . 函数名 ( ) } } > < / tag> (最优解,方便传参)3. 在事件处理函数绑定位置用 bind 修改 this 指向(该方法的缺点是函数不方便传参)< tag onClick= { this . 函数名 . bind ( this ) } > < / tag>
2.关于合成事件与事件对象
注意:React 框架中的事件是合成事件(SyntheticEvent),其事件对象也是合成对象,不同于原生 js 中讲的事件对象(合成事件是在 js 原生事件的基础上进行了二次封装,对事件进行兼容性处理,使其在不同的浏览器表现相同,并添加了一些额外的方法;使用驼峰命名法的事件都是合成事件)
产生目的:React 为了避免这类 DOM 事件滥用造成性能问题,同时屏蔽底层不同浏览器之间的事件系统差异,实现了一个中间层——SyntheticEvent
原理:
1. React 在初始化时会绑定一个 document 的事件代理,用于处理所有的合成事件,这个代理会在组件卸载时被移除。
2. 当一个 DOM 元素上的事件被触发时,React 会根据事件类型创建一个合成事件对象,这个对象是基于原生事件对象包装而成的,并添加了一些额外的属性,如 type、target、currentTarget 等。
3. 在创建合成事件对象时,React 会先从事件池中获取一个已经存在的合成事件对象,如果不存在则创建一个新的合成事件对象,这个池子可以重复利用已经创建的合成事件对象,避免大量创建对象导致的性能问题。
4. React 会在合成事件对象上添加一些额外的属性和方法,如stopPropagation(阻止冒泡)、preventDefault(阻止默认行为)等,并将一些原生事件对象上的属性值赋值到合成事件对象中。
5. 最后,React 会将合成事件对象传递给事件处理函数,开发者可以通过访问合成事件对象的属性和方法来处理事件。
6. 事件处理函数执行完毕后,React 会将合成事件对象的属性值重置,然后将合成事件对象放回事件池中,以便下次重复利用。
ps:不要将原生事件(addEventListener)和 React合成事件一起混合使用,这两个机制是不一样的
< button onClick= { ( e ) => { this . handleClick ( 10 , e) } } > 点击< / button> (当箭头函数包裹的事件处理函数需要使用到事件对象时,需要手动传参,因为此时事件对象默认传给了外层的箭头函数,套在里面的事件处理函数拿不到事件对象)
3.props与state,setState方法
1. 区别:1. props是用来接收来自父组件的属性的一个js对象,这个数据流可以一直传递到子孙组件, 是只读的2. state是用来定义组件自身的状态的一个js对象, 是可变的, 建议通过setState方法更新组件状态的值
2. this . setState ( ) 方法的底层原理:(这个方法想要触发render函数,就必须有参数,至少要写一个空对象作为他的参数,无参则无法触发组件更新)
该方法的底层原理主要包括两个方面:组件状态(变量)更新+ dom节点更新
在执行的时候会拿传入的新对象和原有的this . state对象进行合并,同时会触发组件更新( 由于setState是个异步操作, 所以组件状态的更新并不是立即进行的。 而是会放入到异步队列中, 等到事件循环到时再执行( 如果在同一个事件循环中有多个异步操作,它们会一次性同步到state中 ) ;
接下来会依次调用组件更新期的相关生命周期函数(比如: render函数), 然后会通过render生成一个新的虚拟dom树,拿新的虚拟dom树和之前的虚拟dom树进行对比(使用diff算法), 用最小的代价完成从虚拟dom树到真实dom节点的更新)
4.关于react框架的严格模式标签
标签语法:< React. StrictMode> < / React. StrictMode>
位置:src文件夹下的直接子文件:index. js中
表现:会触发两次render ( ) 函数
原因:
1. 检测不安全的生命周期函数使用
在React的严格模式下,会检测不安全的生命周期函数使用,例如 componentWillUpdate 和 componentWillReceiveProps 等函数,这些函数可能会导致一些潜在的问题,如状态不一致等。通过在严格模式下检测这些问题,可以帮助开发者更早地发现和解决这些问题。
2. 检测遗留的 Context API
在React 16 . x 版本之前,Context API 是使用实验性 API 实现的,可能存在一些问题和不兼容性。在 React 的严格模式下,会检测使用遗留的 Context API ,从而提醒开发者使用新的 Context API 。
3. 检测意外的副作用
React严格模式下还会检测意外的副作用,如意外的副作用产生的副作用等,从而帮助开发者更早地发现和解决这些问题。
4. 检测过时的 findDOMNode API
在React 16 . x 版本之前,可以使用 findDOMNode API 来获取组件的 DOM 节点。但是这个 API 有一些问题,例如会破坏组件的封装性,同时也可能会导致性能问题。在React的严格模式下,会检测使用过时的 findDOMNode API ,从而提醒开发者使用新的 ref API 。
5.关于react组件生命周期
1. 实例化期1. consturctor ( )
2. 挂载期1. componentWillMount ( ) 2. render ( ) (render ( ) 的作用是生成虚拟 dom树来渲染或者更新组件,因此挂载期也需要执行一次)3. componentDidMount ( ) (可以在这里发送网络请求,创建定时器,监听事件)
3. 更新期1. componentWillUpdate ( ) 2. render ( ) 3. componentDidUpdate ( )
4. 卸载期1. componentWillUnmount ( ) (可以在这里取消网络请求,销毁定时器,取消监听事件)
5. 要点1. 挂载期父子组件生命周期函数执行顺序父组件实例化consturctor ( ) ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓父组件挂载前componentWillMount ( ) ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓父组件执行render ( ) ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓子组件实例化consturctor ( ) ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓子组件挂载前componentWillMount ( ) ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓子组件执行render ( ) ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓子组件挂载完成componentDidMount ( ) ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓父组件挂载完成componentDidMount ( ) 2. 更新期父子组件生命周期函数执行顺序父组件更新前componentWillUpdate ( ) ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓父组件执行render ( ) ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓子组件更新前componentWillUpdate ( ) (注意父组件更新时,带动子组件也是更新,不是实例化和挂载)↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓子组件执行render ( ) ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓子组件更新完成componentDidUpdate ( ) ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓父组件更新完成componentDidUpdate ( )
6.关于纯组件与性能优化
我们可以通过避免对代码进行一些不必要的重复执行来提高应用性能,做到这一点,有以下两种思路:
1. 组件生命周期函数
shouldComponentUpdate ( )
该函数使用时需要返回一个布尔值,如果返回true ,则代表当前组件继续更新,
如果返回false ,则代表当前组件放弃更新,render ( ) 函数就不会执行
可以通过一定的条件判断来控制该函数在什么情况下返回true ,什么情况下返回false 示例:在以下代码中,nextProps参数可以获取最新的props对象,nextState参数可以获取最新的state状态,通过this . props获取上一次存储的props对象,两者对比,可以判断父组件传来的值是否有改变,改变则子组件继续更新,不改变子组件放弃更新(这里要注意,前后获取的props还是state都是对象,属于引用类型,不能使用== 或者=== 直接比较,这样比较的是他们的堆空间地址,结果一定是不相等的,没有参考价值,我们需要对比的是他们的内容,所以需要二者都使用JSON . stringify ( ) 方法转换成对象形式的字符串再对比)shouldComponentUpdate ( nextProps, nextState ) { if ( JSON . stringify ( nextProps) == JSON . stringify ( this . props) ) { return false ; } else { return true ; } }
2. 纯组件PureComponent纯组件, 会自动帮我们实现shouldComponentUpdate这个生命周期方法,会自动帮我们判断新旧props是否发生变化,进行决定当前组件是否放弃更新, 目的是为了实现组件性能优化(这个组件需要手动引入,用该组件代替原本 class 函数继承的Component组件)
7.关于网络请求
步骤:
1. npm i axios下载axios插件↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
2. 创建utils文件夹,在其中创建request. js文件↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
3. 在文件中导入axios,import axios↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
4. 实例化axios,使用axios. create ( { timeout : 10 * 1000 , baseURL : '/' } ) ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
5. 设置拦截器(请求拦截器 ( 这里添加全局请求头) + 响应拦截器)↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
6. 创建API 文件夹,在其中创建index. js文件,用于请求函数的二次封装↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
7. 设置服务器请求代理(在src文件夹下创建直接子文件,命名为:setupProxy. js,在这个文件中添加服务器请求代理,注意这里文件的位置和命名都是固定的,在ts语法中也不需要更改,错了就起不到作用)
const { createProxyMiddleware : proxy } = require ( "http-proxy-middleware" ) ;
module. exports = ( app ) => { app. use ( "/公共前缀" , proxy ( { target : "http://+ip+端口" , changeOrigin : true } ) )
}