目录
说说你对react的理解?有哪些特性?
说说Real diff算法是怎么运作的?
说说React生命周期有哪些不同的阶段?每个阶段对应的方法是?
说说你对React中虚拟dom的理解?
什么是react中的diff算法?
说说你对react hook的理解?
React组件之间如何通信?
说说你对受控组件和非受控组件的理解?应用场景?
说说Connect组件的原理是什么?
说说react 中jsx语法糖的本质?
说说你对redux中间件的理解?常用的中间件有哪些?实现原理?
说说AMD、CMD、commonJS模块化规范的区别?
说说package.json中版本号的规则?
说说React jsx转换成真实DOM的过程?
说说你对@reduxjs/toolkit的理解?和react-redux有什么区别?
React render方法的原理,在什么时候会触发?
React性能优化的手段有哪些?
如何通过原生js实现一个节流函数和防抖函数?
说说你对koa中洋葱模型的理解?
说说如何借助webpack来优化前端性能?
说说你对webSocket的理解?
(1)用于构建用户界面的 JavaScript 库,只提供了 UI 层面的解决方案
(2)遵循组件设计模式、声明式编程范式和函数式编程概念,以使前端应用程序更高效
(3)使用虚拟 DOM 来有效地操作 DOM,遵循从高阶组件到低阶组件的单向数据流
(4)帮助我们将界面成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,构成整体页面
(5)react 类组件使用一个名为 render() 的方法或者函数组件return,接收输入的数据并返回需要展示的内容
特性:
JSX 语法
单向数据绑定
虚拟 DOM
声明式编程
Component
react中diff算法主要遵循三个层级的策略:
tree层级
conponent 层级
element 层级
tree层不会做任何修改,如果有不一样,直接删除创建
component层从父级往子集查找,如果发现不一致,直接删除创建
element层有key值做比较,如果发现key值可以复用的话,就会将位置进行移动,如果没有,则执行删除创建
创建阶段:
constructor
getDerivedStateFromProps
render
componentDidMount
更新阶段:
getDerivedStateFromProps
shouldComponentUpdate
render
getSnapshotBeforeUpdate
componentDidUpdate
销毁阶段:
componentWillUnmount
在传统的 Web 应用中,我们往往会把数据的变化实时地更新到用户界面中,每次微小的数据变动
都会引起 DOM 树的重新渲染。而虚拟DOM则是将所有操作累加起来,统计计算出所有的变化
后,统一更新一次DOM。
原理:
当Node节点的更新,虚拟DOM会比较两棵DOM树的区别,保证最小化的DOM操作,使得执行效率得到保证。计算两棵树的常规算法是O(n^3)
级别,所以需要优化深度遍历的算法。React diff算法的时间复杂度为O(n)。
出现的原因:
当Node节点的更新,虚拟DOM会比较两棵DOM树的区别,保证最小化的DOM操作,使得执行效率得到保证。
计算两棵树的常规算法是O(n^3)
级别,而React diff算法的时间复杂度为O(n)
优化内容:
React 分别对 tree diff、component diff 以及 element diff 进行算法优化。
tree层不会做任何修改,如果有不一样,直接删除创建
component层从父级往子集查找,如果发现不一致,直接删除创建
element层有key值做比较,如果发现key值可以复用的话,就会将位置进行移动,如果没有,则执行删除创建
Hook是 React 16.8 的新增特性,可以让你在不编写class的情况下使用state以及其他的React特性
解决的问题:
难以重用和共享组件中的与状态相关的逻辑
逻辑复杂的组件难以开发与维护
类组件中的this增加学习成本
类组件在基于现有工具的优化上存在些许问题
由于业务变动,函数组件不得不改为类组件等等
父组件向子组件传递:
父组件在调用子组件的时候,在子组件标签内传递参数,子组件通过props属性就能接收父组件传递过来的参数
子组件向父组件传递:
父组件向子组件传一个函数,然后通过这个函数的回调,拿到子组件传过来的值
兄弟组件之间的通信:
父组件作为中间层来实现数据的互通,通过使用父组件传递
父组件向后代组件传递:
使用context提供了组件之间通讯的一种方式,可以共享数据,其他数据都能读取对应的数据
通过使用React.createContext创建一个context;
context创建成功后,其下存在Provider组件用于创建数据源,Consumer组件用于接收数据
Provider组件通过value属性用于给后代组件传递数据
如果想要获取Provider传递的数据,可以通过Consumer组件或者或者使用contextType属性接收
非关系组件传递:
将数据进行一个全局资源管理,从而实现通信
受控组件:
简单来讲,就是受我们控制的组件,组件的状态全程响应外部数据
class TestComponent extends React.Component {
constructor (props) {
super(props);
this.state = { username: 'lindaidai' };
}
render () {
return
}
}
当我们在输入框输入内容的时候,会发现输入的内容并无法显示出来,也就是input标签是一个可读的状态
这是因为value被this.state.username所控制住。当用户输入新的内容时,this.state.username并不会自动更新,这样的话input内的内容也就不会变了
如果想要解除被控制,可以为input标签设置onChange事件,输入的时候触发事件函数,在函数内部实现state的更新,从而导致input框的内容页发现改变
非受控组件:
简单来讲,就是不受我们控制的组件
一般情况是在初始化的时候接受外部数据,然后自己在内部存储其自身状态
当需要时,可以使用ref 查询 DOM并查找其当前值
应用场景:
connect是一个高阶函数,它真正连接 Redux 和 React,包在我们的容器组件的外一层,接收上面 Provider 提供的 store 里面的 state 和 dispatch,传给一个构造函数,返回一个对象,以属性形式传给我们的容器组件。
原理:
首先传入mapStateToProps、mapDispatchToProps,然后返回一个生产Component的函数(wrapWithConnect),然后再将真正的Component作为参数传入wrapWithConnect,这样就生产出一个经过包裹的Connect组件,该组件具有:
(1)通过props.store获取祖先Component的store
(2)props包括stateProps、dispatchProps、parentProps,合并在一起得到nextState,作为props传给真正的Component
(3)componentDidMount时,添加事件this.store.subscribe(this.handleChange),实现页面交互
(4)shouldComponentUpdate时判断是否有避免进行渲染,提升页面性能,并得到nextState
(5)componentWillUnmount时移除注册的事件this.handleChange
jsx是JavaScript的一种语法扩展,它跟模板语言很接近,但是它充分具备JavaScript的能力
JSX就是用来声明React当中的元素,React使用JSX来描述用户界面
JSX语法糖允许前端开发者使用我们最熟悉的类HTML标签语法来创建虚拟DOM在降低学习成本
理解:
中间件是介于应用系统和系统软件之间的一类软件,它使用系统软件所提供的基础服务(功能),衔接网络上应用系统的各个部分或不同的应用,能够达到资源共享、功能共享的目的
Redux中,中间件就是放在就是在dispatch过程,在分发action进行拦截处理
本质上一个函数,对store.dispatch方法进行了改造,在发出 Action和执行 Reducer这两步之间,添加了其他功能
常用中间件:
redux-thunk:用于异步操作
redux-logger:用于日志记录
实现原理:
所有中间件被放进了一个数组chain,然后嵌套执行,最后执行store.dispatch。可以看到,中间件内部(middlewareAPI)可以拿到getState和dispatch这两个方法
内部会将dispatch进行一个判断,然后执行对应操作
(1)AMD/CMD/CommonJs 是js模块化开发的规范,对应的实现是require.js/sea.js/Node.js
(2)CommonJs 主要针对服务端,AMD/CMD/ES Module主要针对浏览器端,容易混淆的是AMD/CMD
(3)AMD是预加载,在并行加载js文件同时,还会解析执行该模块;而CMD是懒加载,虽然会一开始就并行加载js文件,但是不会执行,而是在需要的时候才执行
(4)AMD优点:加载快速,尤其遇到多个大文件,因为并行解析,所以同一时间可以解析多个文件;AMD缺点:并行加载,异步处理,加载顺序不一定,可能会造成一些困扰,甚至为程序埋下大坑。
(5)CMD优点:因为只有在使用的时候才会解析执行js文件,因此,每个JS文件的执行顺序在代码中是有体现的,是可控的;CMD缺点:执行等待时间会叠加。因为每个文件执行时是同步执行(串行执行),因此时间是所有文件解析执行时间之和,尤其在文件较多较大时,这种缺点尤为明显。
(6)如何使用:CommonJs 的话,因为 NodeJS 就是它的实现,所以使用 node 就行,也不用引入其他包。AMD则是通过标签引入require.js,CMD则是引入sea.js
version 指定版本号
>version 大于该版本号
>=version 大于等于该版本号
<=version 小于等于该版本号 ~version 右侧任意 ^version 从左向右,第一个非0号的右侧任意 x-version x位置任意 " "|| * version 表示版本任意 version1-version2 表示版本区间范围 包含首尾版本号 version1||version2||…version 表示或,或version1或version2,支持多个 使用React.createElement或JSX编写React组件,实际上所有的 JSX 代码最后都会转换成React.createElement(...) ,Babel帮助我们完成了这个转换的过程。 createElement函数对key和ref等特殊的props进行处理,并获取defaultProps对默认props进行赋值,并且对传入的孩子节点进行处理,最终构造成一个虚拟DOM对象 ReactDOM.render将生成好的虚拟DOM渲染到指定容器上,其中采用了批处理、事务等机制并且对特定浏览器进行了性能优化,最终转换为真实DOM reduxjs/toolkit: Redux 官方强烈推荐,开箱即用的一个高效的 Redux 开发工具集。它旨在成为标准的 Redux 逻辑开发模式,使用 Redux Toolkit 都可以优化你的代码,使其更可维护 react-redux: react官方推出的redux绑定库,react-redux将所有组件分为两大类:UI组件和容器组件,其中所有容器组件包裹着UI组件,构成父子关系。容器组件负责和redux交互,里面使用redux API函数,UI组件负责页面渲染,不使用任何redux API。容器组件会给UI组件传递redux中保存对的状态和操作状态的方法 原理: 在类组件中render函数指的就是render方法;而在函数组件中,指的就是整个函数组件 render函数中的jsx语句会被编译成我们熟悉的js代码,在render过程中,react将新调用的render函 数返回的树与旧版本的树进行比较,这一步是决定如何更新 DOM 的必要步骤,然后进行 diff 比 较,更新dom树 触发时机: 类组件调用 setState 修改状态 函数组件通过useState hook修改状态 一旦执行了setState就会执行render方法,useState 会判断当前值有无发生改变确定是否执行 render方法,一旦父组件发生渲染,子组件也会渲染 1.避免使用内联函数 2.使用react fragement 避免额外标记 3.使用immutable,减少渲染的次数,为了避免重复渲染,会在shouldComponentUpdate()中做对 比,当返回true,执行render方法。immutable通过is方法完成对比 4.懒加载组件 5.事件绑定方式(在constructor中使用bind绑定性能更高) 6.服务端渲染 7.组件拆分,合理使用hooks 防抖: 节流: 使用监听模式或热更新热替换 开发环境不做无意义的操作 选择一个合适的devtool属性值 代码压缩用ParallelUglifyPlugin代替自带的 UglifyJsPlugin插件 代码压缩用ParallelUglifyPlugin代替自带的 UglifyJsPlugin插件 使用fast-sass-loader代替sass-loader babel-loader开启缓存 不需要打包编译的插件库换成全局
说说React jsx转换成真实DOM的过程?
说说你对@reduxjs/toolkit的理解?和react-redux有什么区别?
React render方法的原理,在什么时候会触发?
React性能优化的手段有哪些?
如何通过原生js实现一个节流函数和防抖函数?
const debounce = (func, wait = 50) => {
let timer = 0
return function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
func.apply(this, args)
}, wait)
}
}
export const throttle = function (fn, wait = 500) {
let flg = true
return function () {
if (!flg) return;
flg = false
setTimeout(() => {
fn.apply(this, arguments)
flg = true
}, wait);
}
}
说说你对koa中洋葱模型的理解?
Koa
的洋葱模型指的是以 next()
函数为分割点,先由外到内执行 Request
的逻辑,再由内到外执行 Response
的逻辑。通过洋葱模型,将多个中间件之间通信等变得更加可行和简单。其实现的原理并不是很复杂,主要是 compose
方法。在洋葱模型中,每一层相当于一个中间件,用来处理特定的功能,比如错误处理、Session
处理等等。其处理顺序先是 next()
前请求(Request
,从外层到内层)然后执行 next()
函数,最后是 next()
后响应(Response
,从内层到外层),也就是说每一个中间件都有两次处理时机说说如何借助webpack来优化前端性能?