React面试题总结
- 1.props和state相同点和不同点?render方法在哪些情况下会执行?
- 2.shouldComponentUpdate有什么作用?
- 3.说说React中的虚拟dom?在虚拟dom计算的时候diff和key之间有什么关 系?
- 4.react新出来两个钩子函数是什么?和删掉的will系列有什么区别?
- 5.React的props.children使用map函数来遍历会收到异常显示,为什么应该如何遍历?
- 6.React组件之间如何通信?
- 7.谈谈你对immutable.js的理解?
- 8.redux本来是同步的,为什么它能执行异步代码?实现原理是什么?中间件的 实现原理是什么?
- 9.redux中同步action与异步action最大的区别是什么?
- 10.redux-saga和redux-thunk的区别与使用场景?
- 11.在使用redux过程中,如何防止定义的action-type的常量重复?
- 12.CDN的特点及意义?
- 13.为什么for循环比forEach性能高?
- 14.说说你对@reduxjs/toolkit的理解?和react-redux有什么区别?
- 15.React render方法的原理,在什么时候会触发?
- 16.![] == ![],![] == [],结果是什么?为什么?
- 17.什么是闭包,应用场景是什么?
- 18.谈谈你是如何做移动端适配的
- 19.移动端1像素的解决方案
- 20.弹性盒中的缩放机制是怎样的
1.props和state相同点和不同点?render方法在哪些情况下会执行?
不同点:
1.props不可以在组件内部修改,但state可以在组件内部修改
2.可以从父组件修改自组件的props,而不能从父组件修改自组件的state
相同点:
1.props和state都是导出HTML的原始数据。
2.props和state都是确定性的,如果我们写的组件为同一props和state的组合生成了不同的输出,那木我们肯定在哪里做错了
4.props和state都会触发渲染更新
5.props和state都是纯JS对象(用typeof来判断,结果都是object)
6.可以从父组件得到初始值props和state的初始值
触发时机:
类组件调用 setState
修改状态
函数组件通过useState hook
修改状态
一旦执行了setState
就会执行render
方法,useState
会判断当前值有无发生改变确定是否执行render
方法,一旦父组件发生渲染,子组件也会渲染
2.shouldComponentUpdate有什么作用?
shouldComponentUpdate () 的返回值用于判断 React 组件的输出是否受当前 state 或 props 更改的影响,当 props 或 state 发生变化时,shouldComponentUpdate () 会在渲染执行之前被调用
3.说说React中的虚拟dom?在虚拟dom计算的时候diff和key之间有什么关 系?
虚拟dom理解:
实际上它只是一层对真实DOM的抽象,以JavaScript对象(VNode节点)作为基础的树,用对象的属性来描述节点,最终可以通过一系列操作时这棵树映射到真实环境上,创建虚拟DOM就是为了更好将虚拟的节点渲染到页面视图中,所以虚拟DOM对象的节点与真实DOM的属性一一照应
关系:
key 当同一层级的某个节点添加了对于其他同级节点唯一的key属性,当它在当前层级的位置发生了变化后。react diff算法通过新旧节点比较后,如果发现了key值相同的新旧节点,就会执行移动操作(然后依然按原策略深入节点内部的差异对比更新),而不会执行原策略的删除旧节点,创建新节点的操作
4.react新出来两个钩子函数是什么?和删掉的will系列有什么区别?
新生命周期中新增了两个钩子,分别为getDerivedStateFromProps(从props中得到衍生的state)和getSnapshotBeforeUpdate。
区别:
1、componentWillMount中可能需要做的事(一些数据初始化的操作就应该放在这个钩子中处理),constructor与componentDidMount也能做,甚至做的更好,此方法被废弃。
2、componentWillReceiveProps实际行为与命名并不相符,由于不稳定性已由getDerivedStateFromProps代替;
3、而componentWillUpdate同等理由被getSnapshotBeforeUpdate代替
5.React的props.children使用map函数来遍历会收到异常显示,为什么应该如何遍历?
在reactJS 中 props.children 不一定是数组,
有三种可能 :
1当前组件没有子节点数据类型就是undefined,
2有一个子节点数据类型就是object 。
3 有多个子节点的时候才会是array ,只有在多个节点的时候才可以直接调用map方法,react资深提供了一个react.children.map()方法,可以安全遍历子节点对象。
6.React组件之间如何通信?
- 父组件向子组件通讯:
父组件可以向子组件传入props
的方式,向子组件进行通讯。 - 子组件向父组件通讯:
props
+回调的方式,父组件向子组件传递props
进行通讯,此props
为作用域为父组件自身的函数,子组件调用该函数,将子组件想要传递的信息,作为参数,传递到⽗组件的作⽤域中。 - 兄弟组件通信:
兄弟组件之间的传递,则父组件作为中间层来实现数据的互通,通过使用父组件传递
例:组件A – 传值 --> 父组件 – 传值 --> 组件B - 跨层级通讯:
Context
设计⽬的是为了共享那些对于⼀个
组件树⽽⾔是“全局”的数据,
使用context
提供了组件之间通讯的一种方式,可以共享数据,其他数据都能读取对应的数据
例如当前认证的⽤户、主题或⾸选语⾔,对于跨越多层的全局数据通过Context
通信再适合不过。 - 发布订阅者模式:
发布者发布事件,订阅者监听事件并做出反应,我们可以通过引⼊event
模块进⾏通信。 - 全局状态管理工具:
借助Redux
或者Mobx
等全局状态管理⼯具进⾏通信,这种⼯具会维护⼀个全局状态中⼼Store
,并根据不同的事件产⽣新的状态。
7.谈谈你对immutable.js的理解?
mutable.js采用了 持久化数据结构 ,保证每一个对象都是不可变的,任何添加、修改、删除等操作都会生成一个新的对象,且通过 结构共享 等方式大幅提高性能
8.redux本来是同步的,为什么它能执行异步代码?实现原理是什么?中间件的 实现原理是什么?
Redux本身是一个同步的状态管理库,但通过使用中间件(middleware),可以实现在Redux中执行异步代码。
在Redux中,中间件是一种位于action被发起和reducer处理之间的拦截器。它可以拦截action,并对其进行处理,甚至可以发起新的action。中间件提供了一种扩展Redux功能的机制,使得我们可以处理异步操作、日志记录、错误处理等。
Redux中使用中间件执行异步代码的原理是基于以下几个步骤:
**1. 创建中间件函数:**中间件函数是一个接收store
对象作为参数的函数,它返回一个函数,该函数接收next
作为参数。
**2. 应用中间件:**通过调用Redux的applyMiddleware
函数,将中间件函数作为参数传递给它,并将返回的函数作为Redux store的enhancer。这样就将中间件应用到了Redux的执行流程中。
3. 拦截action:当发起一个action时,中间件会捕获到这个action,并在需要的情况下进行处理。中间件可以访问到当前的store
对象,可以获取state、dispatch新的action等。
4. 执行异步操作:在中间件中,我们可以执行异步的操作,如发送网络请求、获取数据等。通常使用异步操作库(如axios、fetch)或者Promise来执行异步操作。
5. 发起新的action:当异步操作完成后,中间件可以根据异步操作的结果,发起新的action来更新Redux的状态。这个新的action会经过其他中间件的拦截,最终被传递给reducer进行状态更新。
通过这种方式,Redux中间件实现了在同步的Redux流程中执行异步代码的能力。它允许我们在Redux中处理异步操作,并将异步结果以同步的方式更新到状态中。
6.中间件的实现原理是,它在Redux的dispatch过程中拦截action,并可以对action进行处理、修改或者发起新的action。中间件形成了一个链式调用的机制,每个中间件都可以对action进行处理,然后将处理结果传递给下一个中间件,最终传递给reducer进行状态更新。这种链式调用的机制使得我们可以在Redux流程中插入自定义的逻辑,并对action进行灵活的处理。
9.redux中同步action与异步action最大的区别是什么?
同步: Redux的教程中反复使用todo列表的例子,那就是个典型的同步action,每当disptach action时,state就会被立即更新[当然setState是异步的]
异步: 一般异步处理都会使用中间件,比如redux-thunk或者redux-saga,他们做的事情是包装dispatch,request action由view触发,receive action由这些中间件触发
10.redux-saga和redux-thunk的区别与使用场景?
redux-thunk:通过执行action中的函数实现业务逻辑,没有拓展API
redux-saga:通过定义saga函数进行监控,同时提供一些常用的API
redux-thunk:将部分异步处理业务逻辑写在action中,redux-sagasaga则是放在监控的函数中
11.在使用redux过程中,如何防止定义的action-type的常量重复?
ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。
Symbol函数前不能使用new命令,否则会报错。这是因为生成的Symbol是一个原始类型的值,不是对象
Symbol函数可以接受一个字符串作为参数,表示对Symbol实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。
12.CDN的特点及意义?
DN的功能特点:
(1)节省骨干网带宽,减少带宽需求量;
(2)提供服务器端加速,解决由于用户访问量大造成的服务器过载问题;
(3)服务商能使用Web
Cache技术在本地缓存用户访问过的Web页面和对象,实现相同对象的访问无须占用主干的出口带宽,并提高用户访问因特网页面的相应时间的需求;
(4)能克服网站分布不均的问题,并且能降低网站自身建设和维护成本;
(5)降低“通信风暴”的影响,提高网络访问的稳定性
意义
使用CDN可以获取一些好处,无论它们是公有CDN还是提供静态内容的私有CDN,你的里程可能会有所不同,具体取决于通过CDN传递的流量以及你产生的流量。
13.为什么for循环比forEach性能高?
对于 arraylist,是顺序表,使用 for 循环可以顺序访问,速度较快;使用 foreach 会比 for 循环稍慢一些。对于 linkedlist,是单链表,使用 for 循环每次都要从第一个元素读取 next 域来读取,速度非常慢;使用 foreach 可以直接读取当前结点,数据较快;
区别:
遍历:for循环按照顺序进行遍历,forEach使用iterator迭代器遍历
数据结构:for循环是随机访问元素,foreach是顺序链表访问元素
性能上:对于数组arraylist来说,是顺序表,使用for循环可以进行顺序访问,速度比较快;使用foreach循环会比for循环稍微慢一点。对于linedlist来说,是单链表,使用for循环每次都要从第一个元素读取next域来读取,速度非常慢;使用foreach可以直接读取当前的节点,数据较快。
14.说说你对@reduxjs/toolkit的理解?和react-redux有什么区别?
react-redux 是的官方 React UI 绑定层,允许您的 React 组件从 Redux 存储中读取数据,并将操作分派到存储以更新状态。
@reduxjs/toolkit 是对 Redux 的二次封装,开箱即用可的一个高效的 Redux 开发工具集,使得创建store、更新store更加方便
15.React render方法的原理,在什么时候会触发?
原理:
在类组件中render
函数指的就是render
方法;而在函数组件中,指的就是整个函数组件
render
函数中的jsx
语句会被编译成我们熟悉的js代码,在render
过程中,react
将新调用的render
函数返回的树与旧版本的树进行比较,这一步是决定如何更新 DOM 的必要步骤,然后进行 diff
比较,更新dom树
触发时机:
类组件调用 setState
修改状态
函数组件通过useState hook
修改状态
一旦执行了setState
就会执行render
方法,useState
会判断当前值有无发生改变确定是否执行render
方法,一旦父组件发生渲染,子组件也会渲染
16.![] == ![],![] == [],结果是什么?为什么?
结果两个 都是true
1. ![] == ![]
首先是!的优先级要比 == 高 所以 先执行两边的 ![] 然后单个的[]是true 加上!取反 也就是false了
然后 第一个 ![] == ![] 也就是等于 false == false 最后返回的是true
2. ![] == []
然后后边的![] == [] 也是因为!优先级高 所以先把左边的变成false == []
然后又因为 两个值相比较 如果有一方的值是布尔值的话 就会把另一方转成数值
然后 [] 转成数值的话 就是 0 然后因为0 = false 所以最后 也是false == false 最后也返回一个true
17.什么是闭包,应用场景是什么?
闭包的理解:
闭包就是一个函数定义在另一个函数的内部 这个内部的函数就是闭包 并且闭包函数可以访问函数内部的局部变量或私有变量 并且闭包可以形成封闭私有空间 不受外部影响 还可以让变量的值始终保存到内存中
闭包使用场景 :
- 创建私有变量
- 延长变量的声明周期
- 定时器传参
- 回调和立即执行函数
- 创建防抖,节流函数
18.谈谈你是如何做移动端适配的
- flex弹性布局
- 百分比
- 用框架搭建页面
- viewport适配
- 媒体查询media
- rem+viewport缩放
19.移动端1像素的解决方案
- 移动端1像素的解决方案?
- 伪类+transform
- viewport + rem
- border-image
- background-image
- postcss-write-svg
20.弹性盒中的缩放机制是怎样的
弹性盒中的项目设置flex-grow属性定义项目的放大比例,默认值为0,值越大,放大越厉害,且不支持负值;
而flex-shrink属性定义项目的缩小比例,默认值为1,数值越大,缩小越厉害,同样不支持负值;
flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间,浏览器根据这个属性,计算主轴是否有多余空间。他的默认值为auto,也就是项目的本来大小。
注意:它可以设为跟width或height属性一样的值,比如给具体的像素值,则项目将占据固定空间。
例如
弹性盒子是基于总宽度减去子元素本身占据的宽度, 剩下的宽度, 按照弹性盒子的比例去分配, 比如总宽度是1440, 子元素占据的宽度2003=600 所以可以弹性的宽度是1440-2003=840,
剩下的宽度分成4份, 840/4=210, 所以第一个div: 200+210=410, 第二个div: 200+210*2=620 第三个div和第一个一样200+210=410