前端面试题
1. props和state相同点和不同点?render方法在哪些情况下会执行?
props:
props是一个从外部传进组件的参数,由于React具有单向数据流的特性,所以他的主要作用是从父组件向子组件中传递数据,它是不可改变的,如果想要改变它,只能通过外部组件传入新的props来重新渲染子组件,否则子组件的props和展示形式不会改变,props除了可以传字符串,数字,还可以传递对象,数组甚至是回调函数。
state:
state主要作用是用于组件保存,控制及修改自己的状态,它只能在constructor中初始化,state是可以被改变的,state放改动的一些属性,比如点击选中,再点击取消,类似这种属性就放入带state中,
注意:没有state的叫做无状态组件,多用props少用state,多写无状态组件,注意:修改state的值时,必须通过调用setState方法,当我们调用this.setState方法时,React会更新组件的数据状态,并且重新调用render方法。
不同点:
1.props不可以在组件内部修改,但state可以在组件内部修改
2.可以从父组件修改自组件的props,而不能从父组件修改自组件的state。
相同点:
1.props和state都是导出HTML的原始数据。
2.props和state都是确定性的,如果我们写的组件为同一props和state的组合生成了不同的输出,那木我们肯定在哪里做错了
3.props和state都会触发渲染更新
4.props和state都是纯JS对象(用typeof来判断,结果都是object)
5.可以从父组件得到初始值props和state的初始值
render方法在哪些情况下会执行?
在类组件和函数组件中,render函数的形式是不同的。
在类组件中render函数指的就是render方法;而在函数组件中,指的就是整个函数组件。
在render函数中的jsx语句会被编译成我们熟悉的js代码
在render过程中,React 将新调用的 render函数返回的树与旧版本的树进行比较,这一步是决定如何更新 DOM 的必要步骤,然后进行 diff 比较,更新 DOM树
触发机制:
类组件调用 setState 修改状态 函数组件通过useState hook修改状态。
函数组件通过useState这种形式更新数据,当数组的值不发生改变了,就不会触发render
总结:
render函数里面可以编写JSX,转化成createElement这种形式,用于生成虚拟DOM,最终转化成真实DOM
在React 中,类组件只要执行了 setState 方法,就一定会触发 render 函数执行,函数组件使用useState更改状态不一定导致重新render
组件的props 改变了,不一定触发 render 函数的执行,但是如果 props 的值来自于父组件或者祖先组件的 state
在这种情况下,父组件或者祖先组件的 state 发生了改变,就会导致子组件的重新渲染
所以,一旦执行了setState就会执行render方法,useState 会判断当前值有无发生改变确定是否执行render方法,一旦父组件发生渲染,子组件也会渲染
2. shouldComponentUpdate有什么作用?
shouldComponentUpdate询问组件是否需要更新的一个钩子函数,判断数据是否需要重新渲染,返回一个布尔值。默认的返回值是true,需要重新render()。若如果返回值是false则不触发渲染,利用这个生命周期函数可以强制关闭不需要更新的子组件来提升渲染性能。 这个方法用来判断是否需要调用 render 方法重新描绘 dom。 因为 dom 的描绘非常消耗性能,如果我们能在 shouldComponentUpdate 方法中能够写出更优化的 dom diff 算法,可以极大的提高性能。
3. 说说React中的虚拟dom?在虚拟dom计算的时候diff和key之间有什么关系?
本题详解:https://blog.csdn.net/beifeng11996/article/details/127489690
虚拟dom的理解 实际上它只是一层对真实DOM的抽象,以JavaScript 对象 (VNode 节点) 作为基础的树,用对象的属性来描述节点,最终可以通过一系列操作使这棵树映射到真实环境上 创建虚拟DOM就是为了更好将虚拟的节点渲染到页面视图中,所以虚拟DOM对象的节点与真实DOM的属性一一照应
虚拟dom的实现原理 React虚拟DOM的实现原理,通过JS模拟网页文档节点,生成JS对象树(虚拟DOM),然后再进一步生成真实的DOM树,再绘制到屏幕。如果后面有内容发生改变,React会重新生成一棵全新的虚拟DOM树,再与前面的虚拟DOM树进行比对diff,把差异的部分打包成patch,再应用到真实DOM,然后渲染到屏幕浏览器。
diff .React需要同时维护两棵虚拟DOM树:一棵表示当前的DOM结构,另一棵在React状态变更将要重新渲染时生成。React通过比较这两棵树的差异,决定是否需要修改DOM结构,以及如何修改。这种算法称作Diff算法。
key 当同一层级的某个节点添加了对于其他同级节点唯一的key属性,当它在当前层级的位置发生了变化后。react diff算法通过新旧节点比较后,如果发现了key值相同的新旧节点,就会执行移动操作(然后依然按原策略深入节点内部的差异对比更新),而不会执行原策略的删除旧节点,创建新节点的操作。这无疑大大提高了React性能和渲染效率
实则用到了diff算法中的element 层对比,详情可见: https://blog.csdn.net/m0_53644435/article/details/123440036
4. react新出来两个钩子函数是什么?和删掉的will系列有什么区别?
React16废弃的生命周期有3个will:
componentWillMount
componentWillReceiveProps
componentWillUpdate
废弃的原因: 是在React16的Fiber架构中,调和过程会多次执行will周期,不再是一次执行,失去了原有的意义。此外,多次执行,在周期中如果有setState或dom操作,会触发多次重绘,影响性能,也会导致数据错乱。
React16的2个新的生命周期:
getDerivedStateFromProps
getSnapshotBeforeUpdate
getDerivedStateFromProps的用法:
触发时机频繁,16.3是在props变化时触发,16.4则改为在每次组件渲染器调用,即无论props变化,组件自己setState,父组件render 都会触发 静态方法,本意是隔离访问组件实例,却造成访问组件的数据和方法十分不便,难以进行数据比较 不能setState,而是返回一个对象来更新state,使用不便,也可能触发多次更新状态 当组件实例化的时候,这个方法替代了componentWillMount(),而当接收到新的 props 时,该方法替代了 componentWillReceiveProps() 和 componentWillUpdate()
getSnapshotBeforeUpdate的用法:
在render之后,更新dom之前,state已更新。可以用来读取dom,强制用户只能在mount阶段读取dom。 getSnapshotBeforeUpdate这个周期在Fiber架构中,只会调用一次。
5. React的props.children使用map函数来遍历会收到异常显示,为什么?应该 如何遍历?
在reactJS 中 props.children 不一定是数组, 有三种可能 :
1、当前组件没有子节点数据类型就是undefined,
2、有一个子节点数据类型就是object 。
3、 有多个子节点的时候才会是array ,只有在多个节点的时候才可以直接调用map方法,
react资深提供了一个react.children.map()方法,可以安全遍历子节点对象。
系统提供React.Children.map()方法安全的遍历子节点对象
6. React组件之间如何通信?
1、父传子:
⽗组件可以通过向⼦组件传 props 的⽅式来实现
2、子传父:
可以采用props+回调的方式
3、兄弟组件通信:
可以通过兄弟节点的共同父节点,由父节点转发信息,实现兄弟间通信
4、跨层级通信:
使用context状态树
5、发布者订阅者模式:
发布者发布事件,订阅者监听到事件后做出反应,可以通过引⼊ event 模块进⾏
6、全局状态管理工具:
可以借助 Redux 或 Mobx以及react-redux 等全局状态管理⼯具进⾏通信,它们会维护⼀个全局状态中⼼(Store),并可以根据不同的事件产⽣新的状态 hooks中帮我们封装好的:useContext和useReducer
7. 谈谈你对immutable.js的理解?
Immutable,不可改变的,在计算机中,即指一旦创建,就不能再被更改的数据
对 Immutable对象的任何修改或添加删除操作都会返回一个新的 Immutable对象
Immutable 实现的原理是 Persistent Data Structure(持久化数据结构):
用一种数据结构来保存数据 当数据被修改时,会返回一个对象,但是新的对象会尽可能的利用之前的数据结构而不会对内存造成浪费 也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变,同时为了避免 deepCopy把所有节点都复制一遍带来的性能损耗,Immutable 使用了 Structural Sharing(结构共享)
如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享
8. redux本来是同步的,为什么它能执行异步代码?实现原理是什么?中间件的 实现原理是什么?
详情: linkhttps://www.cnblogs.com/houjl/p/10165498.html
9. redux中同步action与异步action最大的区别是什么?
同步action:
执行了dispatch函数之后,对应的reducer纯函数立即得到执行,reducer执行完了之后,state立即就改变了,此时用store.getState函数,取到的是最新的state值;
异步action:
原则上redux并没有提供异步action的处理方案,异步的action需要依赖第三方的中间件解决(如redux-thunk),dispatch了一个异步action(本质上是dispatch的一个函数)之后,目标state并不会立即响应,而是要看异步函数内部的逻辑,来决定state什么时候响应.
10. redux-saga和redux-thunk的区别与使用场景?
详情: https://blog.csdn.net/qq_43403486/article/details/120340876