说说你对react的理解?有哪些特性?
React是构建用户界面的JavaScript库,专注于UI层面。使用函数式编程和组件式编程。从高阶组件到低阶组件的单向数据流,使用虚拟dom来有效操作dom。组建可以嵌套组件,从而构建一个复杂的UI界面。每个组件都可以独立地进行开发,然后再组合在一起。在类组件中通过render函数渲染,return返回数据
特性:组件化、单向数据流、虚拟dom、jsx语法
说说Real DOM和Virtual DOM的区别?优缺点?
真实dom总损耗:真实dom完全增删改 + 重绘与渲染,虚拟dom的总损耗:虚拟dom增删改 + 真实dom差异增删改 + 重绘与渲染。真实dom操作简单,但大量的修改真实dom,繁琐还容易导致回流。使用虚拟dom,只需要对比真实dom不同之处,更新差异的真实dom即可,避免了操作大量真实dom导致的回流。虚拟dom还实现了跨平台操作,一套代码,多端运行
说说React生命周期有哪些不同的阶段?每个阶段对应的方法是?
初始化阶段
constructor()
挂载阶段
componentWillMount()
componentDidMount()
更新阶段
componentWillUpdate()
componentDidUpdate()
销毁阶段
componentDidUnmont()
说说React中setState执行机制?
setState是类组件中更新状态的方法
接收两个参数,第一个参数可以是对象也可以是函数,如果是对象,用来更新组件中相对应的状态,如果是函数,它可以接收修改前的状态。第二参数为函数,可以接收修改后的状态。
多次执行setState会合并成一次操作
setState只会更新你想更新的数据,不会影响到状态中其他数据
说说react的事件机制?
React是合成事件,它在原来的基础上对事件对象进行了封装,默认第一个参数就是事件对象。事件不在绑定在调用事件本身元素上,而是以事件委托的形式绑定在了根元素上。使用SyntheticEvent来封装原生事件,提供一致的事件接口
React组件之间如何通信?
- 父传子。在父组件中的子组件上自定义一个属性,其值就是要传递的数据。子组件通过this.props.属性来接收
- 子传父。在父组件中自定义一个回调函数,并在其中的子组件上自定义一个属性,用来传递回调函数。子组件通过this.props.属性来接收,并传值给函数。父组件中的回调函数声明参数来接收传递过来的值
- 兄弟组件传值。将状态提升到共同的父级中,通过子1 传 父,父 传 子2的操作进行传值
- 跨组件通信。创建一个空的context对象,从中解构出Provider和Consumer方法。利用Provider将组件包裹住,value属性进行传值。可以通过Consumer和conTextType对象来接收传递过来的值
说说你对受控组件和非受控组件的理解?应用场景?
受控组件就是受state状态控制,非受控组件是不受state状态控制。
应用场景:举例获取表单元素的值。受控组件,有state状态,在其中声明一个变量,input元素的value绑定该变量,通过onChange和setState来实时改变变量的值,也就是input元素的value值。非受控组件没有state状态,需要借助ref来操作原生don来获取input元素的值。当进行input元素复杂操作的时候,操作原生dom就会非常麻烦
说说你对fiber架构的理解?解决了什么问题?
Fiber是react在16版本引入的新架构,解决一下问题
- 增强可中断性。Fiber采用异步算法,支持中断和重新启动渲染,允许进行更高效的任务调度。
- 提供暂停和恢复能力。Fiber可以暂停渲染操作,进行其他任务(如处理事件),然后再继续渲染操作,大大提高了交互反馈的响应速度。
- 增强优先级调度能力。Fiber支持根据任务优先级进行调度,高优任务可以优先完成,而不是一定按照顺序完成。
- 支持错误边界。Fiber允许将组件分割为小片段,如果某个片段渲染出错,只需要重新渲染该片段而不是整个树。
- 支持更细粒度的调试。使用Fiber可以追踪到渲染过程中的每个阶段,更方便定位问题。
- 增强延迟渲染能力。Fiber支持将部分组件延迟渲染,可以优先渲染 highest priority content。
说说react diff的原理是什么?
Tree层,React 只会对相同层级的节点进行比较,如果节点跨层级移动,会直接删除旧节点,创建新节点。 只有删除、创建操作,没有移动操作。
Component层,如果是同一个类的组件,则会继续往下diff运算,如果不是一个类的组件,那么直接删除这个组件下的所有子节点,创建新的
Element层,对于同一层级的节点,React 会用唯一的 key 来标识,提供了三种操作:插入、移动和删除。React 会尽量复用 key 相同的节点,减少 DOM 操作
说说你对redux中间件的理解?常用的中间件有哪些?实现原理?
Redux中间件增加了redux更多的功能,redux-thunk可以使redux进行异步请求,redux-log可以详细的查看对redux共享数据的操作
Redux-thunk、Redux-log
Redux中间件可以使redux进行异步请求。当dispatch去派发action的时候会进行拦截,返回一个函数(thunk),接受dispatch和setState作为参数,在函数里面进行异步操作,然后返回新的action对象,由state和payload作为参数,在里面进行更新
如何使用css实现一个三角形,写出两种以上方案
- 使用border属性
.triangle {
width: 0;
height: 0;
border-top: 50px solid red;
border-right: 50px solid transparent;
border-left: 50px solid transparent;
}
- 使用伪类
.triangle {
position: relative;
width: 100px;
height: 100px;
}
.triangle:before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 50px;
height: 50px;
background-color: red;
transform: rotate(45deg);
}
什么是强缓存和协商缓存?
强缓存是根据返回头中的 Expires 或者 Cache-Control 两个字段来控制的,都是表示资源的缓存有效时间。
协商缓存是由服务器来确定缓存资源是否可用。 主要涉及到两对属性字段,都是成对出现的,即第一次请求的响应头带上某个字, Last-Modified 或者 Etag,则后续请求则会带上对应的请求字段 If-Modified-Since或者 If-None-Match,若响应头没有 Last-Modified 或者 Etag 字段,则请求头也不会有对应的字段。
说说React jsx转换成真实DOM的过程?
使用React.createElement或JSX编写React组件,实际上所有的 JSX 代码最后都会转换成React.createElement(...) ,Babel帮助我们完成了这个转换的过程。
createElement函数对key和ref等特殊的props进行处理,并获取defaultProps对默认props进行赋值,并且对传入的孩子节点进行处理,最终构造成一个虚拟DOM对象
ReactDOM.render将生成好的虚拟DOM渲染到指定容器上,其中采用了批处理、事务等机制并且对特定浏览器进行了性能优化,最终转换为真实DOM
说说你对@reduxjs/toolkit的理解?和react-redux有什么区别?
@redux Toolkit 是我们官方推荐的编写 Redux 逻辑的方法。它围绕 Redux 核心,并包含我们认为对于构建 Redux 应用必不可少的软件包和功能。Redux Toolkit 建立在我们建议的最佳实践中,简化了大多数 Redux 任务,防止了常见错误,并使编写 Redux 应用程序更加容易。
区别:
1、reduxjs/tookit相对于react-redux来说比较方便,集成了redux-devtools-extension,不需要额外的配置,非常方便
2、reduxjs/tookit集成immutable-js的功能,不需要安装配置使用,提升了开发效率
3、reduxjs/tookit集成了redux-thunk的功能
4、reduxjs/tookit将types、actions、reducers放在一起组成了全新的slices,简化了我们的使用
React render方法的原理,在什么时候会触发?
原理:在render过程中,React 将新调用的 render函数返回的树与旧版本的树进行比较,这一步是决定如何更新 DOM 的必要步骤,然后进行 diff 比较,更新 DOM树
组件初始化、挂载的时候
父组件的props更新时,子组件会触发render进行渲染
组件强制更新的时候
shouldComponentUpdate函数组件返回true的时候
组件触发更新阶段钩子函数的时候
React性能优化的手段有哪些?
- 使用虚拟dom。为每一个列表项都绑定唯一的key值,可以使react清楚的知道列表项的变动,提高性能。
- 使用pureComponent和shouldComponentUpdate来更新组件,当组件中的属性或值真正发生变化的时候,组件才会更新,避免不必要的渲染,消耗性能
- 拆分大型组件,将大型组件拆分成一个个小的可复用组件,减少组件的复杂性
- 使用懒加载,可以利用reactLazy进行懒加载,优先加载首屏,提高加载速度,优化性能
如何通过原生js实现一个节流函数和防抖函数,写出核心代码
节流
Function Jl( func,delay ){
Let timer = null
Return function(…args){
If(!timer){
Timer = setTimeout(()=>{
Func.apply(this,args)
Timer = null
},delay)
}
}
}
防抖
Function Fd(func,delay){
Let timer = null
Return function(…agrs){
clearTimeout(timer)
timer = setTimeout(()=>{
func.apply(this,args)
},delay)
}
}
说说webpack中代码分割如何实现?
Webpack通过方法将代码分割成一个个部分,分开去执行,提高执行效率、渲染性能
使用动态导入。动态导入是一种在运行时动态加载模块的技术,可以用于实现代码分割。在JavaScript代码中使用动态导入语法,Webpack会自动将该模块分割成一个独立的文件,并在需要时异步加载。
说说如何借助webpack来优化前端性能?
- 代码分割:使用 Webpack 的代码分割功能可以将应用程序的代码拆分为多个较小的包,以便在需要时按需加载。这可以减少初始加载时间,并提高页面加载速度。
- 压缩代码:Webpack 提供了多种压缩代码的方法,例如使用 UglifyJsPlugin 插件来压缩 JavaScript 代码,使用 TerserPlugin 插件来压缩 JavaScript 和其他类型的文件。这些插件可以减少文件大小,提高加载速度。
- 提取公共代码:使用 Webpack 的 CommonsChunkPlugin 插件可以将多个包中的公共代码提取到一个单独的包中。这可以减少重复代码的数量,提高加载速度。
- 使用缓存:Webpack 提供了多种缓存方法,例如使用 hard-source-webpack-plugin 插件将构建结果缓存到磁盘上,以减少重复构建的时间。这可以提高构建速度和开发效率。
- 使用 Tree Shaking:Webpack 的 Tree Shaking 功能可以去除未引用的代码,减少最终打包的文件大小。这可以提高加载速度和减少冗余代码。
- 使用 loader:使用适当的 loader 可以将不同类型的文件转换为 Webpack 可以处理的模块。例如,使用 babel-loader 可以将 ES6 语法转换为浏览器可读的 ES5 代码,使用 css-loader 可以将 CSS 文件转换为 JavaScript 模块。
- 使用多线程或分布式构建:使用 Webpack 的多线程或分布式构建功能可以将构建任务分配到多个 CPU 核心或多个服务器上进行,以提高构建速度和效率。
说说javascript内存泄漏的几种情况?
- 未及时清理定时器。如果未及时清理定时器,函数会继续执行,从而占用内存
- 对象循环引用:当两个或多个对象相互引用时,即使没有其他变量引用它们,它们也不会被垃圾回收器清理。
- 闭包:当一个函数可以访问另一个函数的作用域,并且这个作用域包含一些变量,即使这个函数已经执行完毕,这些变量也不会被垃圾回收器清理。
- DOM引用:当一个JavaScript对象引用一个DOM对象,并且这个DOM对象没有被销毁,它也不会被垃圾回收器清理。
全局变量:当一个变量被声明为全局变量,并且没有被销毁,它也不会被垃圾回收器清理。