React 面试题
React
说说对 React 的理解?有哪些特性?
React是一个用于构建用户界面的JavaScript库。
特点:
- 通过对DOM的模拟,最大程度的减少与DOM的交互
- 可以和已知的库很好的配合
- jsx语法
- 组件化
- 单项响应的数据流
说说 Real DOM 和 Virtual DOM 的区别?优缺点?
区别:
- Real DOM是浏览器的真实DOM
- virtual DOM是JavaScript对象
优缺点:
Real DOM的优点:浏览器的原生DOM,可以直接操作
Real DOM的缺点:当DOM结构发生改变时,浏览器需要重新布局。损耗性能
virtual DOM的优点:避免了不必要的DOM操作,提升了性能
virtual DOM的缺点:首次渲染计算量大,需要计算virtual DOM的差异
说说React Jsx转换成真实DOM过程?
React中的JSX是一种语法=糖,它可以让我们在JavaScript中编写类似HTML的代码。当我们在React中使用JSX时,它会被转换成真实的DOM元素。这个过程是由Babel编译器完成的。
Babel编译器 会将JSX转换成React.createElement()函数的调用,然后React根据这个函数的返回值来创建真实的DOM元素。
说说对React中合成事件的理解
- react的合成事件是react中处理浏览器兼容和优化性能的方式
- 通过事件委托的方式大大减少了创建事件监听器数量
- 有原生事件同样的事件接口,解决浏览器兼容问题
- 通过事件池的方式减少事件对象的创建,每次触发一个事件时先回检查事件池中是否有可用的事件对象,如果有则复用,而不是直接创建一个事件对象。这里的事件对象是合成事件对象
react子组件不渲染的方式
类组件
PureComponent继承的方式
import React, {PureComponent} from 'react'
class A extends PureComponent {
render() {
console.log('我渲染了');
return (
<div>
子组件
</div>
);
}
}
export default A;
shuldComponentUpdate生命周期的方式
PureComponent实际上就是比较前后的state和props有没有变化,如果没有就不执行render
函数组件
memo高阶组件的方式
import React, {memo} from 'react';
const A = memo(function a(props) {
console.log('我渲染了');
return (
<div>子组件</div>
);
})
export default A;
说说setState的理解
- 在18版本后是一个纯异步函数
- 如果在一个方法中定义多个setState,React会将多个合成一个
- 在同步的代码中是异步的,在异步的代码中
- 参数说明即可
state和props的区别
在react中组件分为有状态组件和无状态组件,state就是在有状态的组件中的动态的数据。
state:state一般定义在constructor生命周期中,定义在state中的数据可以页面变化。state如果修改的话需要使用this.setState方法去修改state中的数据。
props:props用来实现react组件通信功能,react的一大特性就是组件化。而组件间通信就是通过props参数接收
区别:
props是父组件传进来的参数,且参数不可修改
state是定义在类组件中的参数,这个参数可以修改
super()和super(props)的区别
ES6中通过extends关键实现类的继承,在子类中的constructor函数中必须存在super()而且次方法必须先调用,因为子类如果是继承了一个类的情况下,它是没有this的,通过super方法来将父类的this指向子类。
React中的类组件是基于ES6类的规范去实现的,类组件需要继承React.Conponent类,所以一旦有了继承那么必须在constructor中使用super方法才能初始化this,一旦定义了super方法那么就需要写入props参数,这个参数是父组件传递过来的数据。这个props如果不在constructor中通过super方法初始化的情况下,可以在render方法中获取到。但是如果定义了super方法,那么一定要填入props参数,如果不填props参数会报错
Context状态树的执行流程?
context是react提供的一种传递数据的方式。context状态树使用react库中的createContext函数创建,此函数返回两个对象,provider和consumer。
通过createContext创建context对象,context对象中存有两个函数,provider,consumer。单独导出provider和consumer,默认导出context对象。
在根组件中包裹provider组件,类组件使用静态属性来接收数据 static createContext = context,函数组件使用
** **接收数据在consumer中有一个函数,函数中有一个参数参数值就是provider的值
什么是高阶组件,有什么作用?
高阶组件是一个函数,它接收一个组件并返回一个新的组件。它的作用是:代码复用、渲染劫持、条件渲染
react中路由传递参数的方式?
react-router-dom 分为两个版本 5 和 6 。各个版本传参方式和读取参数的方式不同
5
**三种方式:路径后 ?键=值、路由(/main/:键)传参(路径后/值)、to={{pathname: ' 路由 ',state:{ 键 : 值 } }}**
三种获取参数分别是:props.location.search \ props.match.params \ props.location.state、
6
**三种方式:路径后 ?键=值、路由(/main/:键)传参(路径后/值)、to={{pathname: ' 路由 ',state:{ 键 : 值 } }}**
let [query,setQuery]useSreachParams() query.get('键名') 、useParams().键名、useLocation().state.键名
react如何捕捉异常
- js方法 try ··· catch
- react生命周期 static getDerivedStateFromError componentDidCatch
- 事件监听 window.addEventListener('error',(err)=>{·····})
说说React中setState和replaceState的区别?
setState和replaceState都是用来修改状态的,只不过有一点区别
setState是拿到前一次的state状态和当前的状态合并,最后返回覆盖state状态
replaceState是直接全覆盖state状态,说白了就是替换掉前一次的state状态。
在多数情况下还是使用setState来修改状态较为完善
说说你对fiber架构的理解?解决了什么问题?
当一个应用程序****需要并发来处理多个请求时,那就需要使用线程来处理了,而线程的切换和创建都是会占用系统内部CPU。
而fiber架构是在应用程序内部来处理并发请求,在内部创建多个线程以完成请求。这样能在节省系统CPU的情况下高效的、快速的来处理并发
说说你对redux中间件的理解?常用的中间件有哪些?实现原理?
理解:用来在action和reducer之间拦截,来实现异步、日志、路由跳转等
常用:redux-thunk 处理异步请求、redux-promise使action返回一个promise对象、redux-logger来实现日志,每当state修改了就会记录哪里发生了变化
原理:
import {createStore,applyMiddleware} from 'redux'; import reduxThunk from 'redux-thunk' // 使用applymiddleware函数来创建中间件,将中间件作为参数 const middleware = applyMiddleware(reduxThunk) // reducer是处理dispatch任务,initalState初始化state,参数3为中间件 const store = createStore(reducer, initalState, middleware)
redux中同步action与异步action最大的区别是什么?
同步的action是一个****纯函数,而异步的通过Middleware拦截最后通过dispatch派发同步任务
redux-saga和redux-thunk的区别与使用场景?
redux-saga和redux-thunk都是redux中间件。
redux-thunk处理简单的http请求,简单容易上手
redux-saga处理一些复杂的异步逻辑例如websocket、任务取消、多任务并发
在使用redux过程中,如何防止定义的action-type的常量重复?
- 在定义acton-type时加上一些特殊的前缀和后缀
- 使用redux-action中的createAction函数来创建action-type的值
import {createAction} from ‘redux-actions’ createAction(‘TEST_FIRST’) // 这样定义的使用这种方式生成的action-type名是不会重复的
知道react里面的createPortal么,说说其使用场景?
它是react-dom 中ReactDOM的一个函数
使用场景:在渲染一个弹框或者对话框时。这样可以避免一些样式的冲突。
useEffect的依赖为引用类型如何处理?
将依赖项数组分割为多个基本类型依赖项(如数字或字符串),并将其作为 useEffect 的多个参数。例如:useEffect(() => { ... }, [obj.prop1, obj.prop2, arr.length]);
使用 useRef 钩子引用依赖项,然后将其传递给 useEffect。例如:const depRef = useRef(dep); useEffect(() => { ... }, [depRef.current]);
在传递对象时,使用 Object.assign 或 spread 运算符创建新的对象。例如:useEffect(() => { ... }, [Object.assign({}, obj)]);
说说Real diff算法是怎么运作的?
Diff算法是虚拟DOM的一个必然结果,它是通过新旧DOM的对比,将在不更新页面的情况下,将需要内容局部更新Diff算法遵循深度优先,同层比较的原则- 可以使用
key值,可以更加准确的找到DOM节点**react中diff算法主要遵循三个层级的策略: tree层级 conponent 层级 element 层级tree层不会做任何修改,如果有不一样,直接删除创建component层从父级往子集查找,如果发现不一致,直接删除创建 **element层有key值做比较,如果发现key值可以复用的话,就会将位置进行移动,如果没有,则执行删除创建
为什么react元素有一个$$type属性?
目的是为了防止
XSS 攻击。因为Synbol无法被序列化,所以React可以通过有没有$$typeof属性来断出当前的element对象是从数据库来的还是自己生成的。如果没有$$typeof这个属性,react会拒绝处理该元素。
React的props.children使用map函数来遍历会收到异常显示,为什么?应该** **如何遍历?
如果只有一个子节点时会收到异常显示,因为一个子节点时不是一个数组,不是数组就不能进行使用map函数。
应该使用****React中的一个函数Children中的toArray()方法来将单个节点转换成数组类型。转换后就可以遍历了
谈谈你对immutable.js的理解?
Immutable.js是****Facebook开发的一个JavaScript库,它提供了一系列的数据结构和方法来帮助我们创建不可变的数据对象。
Immutable.js提供了几种常见的不可变数据结构,比如****List、Map、Set等,这些数据结构支持函数式编程范式中的高阶操作,例如map、filter、reduce等用于处理数组的方法,可以让你轻松地对数据进行增、删、查、改等一系列操作。
Immutable.js与React有着天然的结合点。React推崇“单向数据流”,而Immutable.js正好符合这个思路,它可以让我们在React的应用中更加灵活地控制状态树,同时通过使用shouldComponentUpdate生命周期钩子可以帮助我们完成对组件更新的优化。
调和阶段setState干了什么?
在React中,当调用setState方法时,会触发组件的重新渲染。setState实际上是对组件状态的更新,它将新的状态合并到现有的状态中,并调用相应的生命周期方法和重绘组件。
在调和阶段,React会根据新的状态和先前的状态进行比较,判断哪些部分需要重新渲染。如果React决定重新渲染组件,它将首先调用shouldComponentUpdate方法检查是否应该进行重新渲染,如果返回false,则跳过渲染过程。如果shouldComponentUpdate返回true,则React将调用render方法进行重新渲染,并根据新的虚拟DOM生成实际的DOM元素,并最终更新到页面中。
简而言之,setState方法在调和阶段做了以下几件事:
- 更新组件状态;
- 判断是否需要重新渲染组件;
- 如果需要重新渲染,根据新的虚拟DOM生成实际的DOM元素,并最终更新到页面中。
react不同版本都有什么变化
- 16版本引入了fiber架构
- 16.3引入了suspense和error Boundaries,可以更好的处理异步请求和错误处理
- 16.3引入了严格模式、新增了部分生命周期代替了旧的生命周期
- 16.8版本引入了函数组件的Hooks
- 17版本对于事件处理做了优化,必须加
on的前缀 - 18版本使用Render API更好的控制节点
// 18版本 ReactDOM.createRoot(root).render(<App />); // 18版本之前 ReactDOM.render(<App />, root); - 18版本root组件卸载时触发的api改变成了unmount
// React 17 ReactDOM.unmountComponentAtNode(root); // React 18 root.unmount(); - Fiber架构不同版本的区别
- 15版本采用的stack example 16版本采用了fiber example 数据结构其实就是一个对象,也是一个执行单元
- 特性
- 增量渲染
- 暂停、终止渲染
- 不同更新优先级
- 并发方面新的基础能力
- 增加了异步任务,调用requestIdleCallback api,会在浏览器空闲的时候运行
- 会将虚拟dom树也就是diff虚拟dom树,将虚拟dom变成链表格式,会将父节点和兄弟节点和本身形成一个链表格式