前端面试之React篇
1. 谈谈你对 React 的了解
-
React,用于构建用户界面的 JavaScript 库,只提供了 UI 层面的解决方案
-
遵循组件设计模式、声明式编程范式和函数式编程概念,以使前端应用程序更高效
-
使用虚拟DOM来有效地操作DOM,遵循从高阶组件到低阶组件的单向数据流
-
帮助我们将界面成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,构成整体页面
-
react 类组件使用一个名为 render() 的方法或者函数组件return,接收输入的数据并返回需要展示的内容
React 特点:
- 声明式设计 −React 采用声明范式,可以轻松描述应用。
- 高效 −React 通过对 DOM 的模拟,最大限度地减少与 DOM 的交互。
- 灵活 −React 可以与已知的库或框架很好地配合。
- JSX − JSX 是 JavaScript 扩展语法。React 开发不一定使用 JSX, 但我们建议使用它。
- 组件 − 通过 React 构建组件,代码更容易复用,能够很好的应用在大项目的开发中。
- 单向数据流 − React 实现了单向响应的数据流,从而减少了重复代码,这也是它为什么 比传统数据绑定更简单。
React优势:
- 高效灵活
- 声明式的设计,简单使用
- 组件式开发,提高代码复用率
- 单向响应的数据流会比双向绑定的更安全,速度更快
2.hsah和history的区别
区别一:
生产环境下:两者无区别
开发环境或者测试环境下:
hash:前进和后退正常,刷新页面正常
history:前进和后退正常,刷新页面会报错,报错可能有两种结果:一种是404报错,一种是直接把没有处理的数据展示到页面
history报错的原因:刷新页面,就走后端路由,如果后边没有该路由,就是404,如果有该路由,会直接数据展示
区别二:原理不同
hash采用的是window.onhashchange=()=>{}来实现的
history采用的是HTML5新增的interface里面的pushState()和replaceState(),不兼容ie6~8
建议:工作中用hash,如果要用history,需要与后端人员配合,有冲突的路由优先前端
hash | history |
---|---|
有 # 号 | 没有 # 号 |
实际的url之前使用哈希字符,这部分url不会发送到服务器,不需要在服务器层面上进行任何处理 | 没访问一个页面都需要服务器进行路由匹配生成 html 文件再发送响应给浏览器,消耗服务器大量资源 |
能够兼容到IE8 | 只够兼容到IE10 |
刷新不会存在 404 问题 | 浏览器直接访问嵌套路由时,会报 404 问题。 |
不需要服务器任何配置 | 需要在服务器配置一个回调路由 |
3.声明式编程
声明式编程是一种编程范式,它关注的是你要做什么,而不是如何做它表达逻辑而不显式地定义步骤。
这意味着我们需要根据逻辑的计算来声明要显示的组件。
声明式编程方式使得React组件很容易使用,最终的代码简单易于维护
声明式 VS 命令式
函数式编程是声明式模式,意味着程序的逻辑的表达无需明确的流控制的描述。
命令式程序花费大量的代码描述具体的步骤以获取期望的结果—流控制:如何做。
声明式程序抽象出流控制过程而不是花费大量的代码描述数据流:做什么?怎么做(how)被抽象出来了。
函数式编程(声明式编程的核心)
简单说,"函数式编程"是一种"编程范式",也就是如何编写程序的方法论。
它属于"结构化编程"的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用
特点:
- 函数是"第一等公民"
- 只用"表达式",不用"语句"
- 没有"副作用"
- 不修改状态
- 引用透明
函数式编程主张:
- 纯函数而不是共享状态和副作用
- 基于可变数据的不可变性
- 基于命令式流控制的函数组合
- 大量的通用的,可重用的工具使用高阶函数作用于多种数据类型而不是只能在它们共同协作的数据上操作。
- 声明式的代码而不是命令式的代码(做什么而非怎么做)
- 表达式而不是陈述
- 基于即时多态的容器和高阶函数
优点:
- 代码简洁,开发快速
函数式编程大量使用函数,减少了代码的重复,因此程序比较短,开发速度较快
- 更方便的代码管理
函数式编程不依赖、也不会改变外界的状态,只要给定输入参数,返回的结果必定相同。因此,每一个函数都可以被看做独立单元,很有利于进行单元测试(unit testing)和除错(debugging),以及模块化组合
- 易于"并发编程"
函数式编程不需要考虑"死锁"(deadlock),因为它不修改变量,所以根本不存在"锁"线程的问题。不必担心一个线程的数据,被另一个线程修改,所以可以很放心地把工作分摊到多个线程,部署"并发编程"
函数式编程常用核心概念
- 纯函数
对于相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用,也不依赖外部环境的状态的函数,叫做纯函数
- 函数的柯里化
传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。
事实上柯里化是一种“预加载”函数的方法,通过传递较少的参数,得到一个已经记住了这些参数的新函数,某种意义上讲,这是一种对参数的“缓存”,是一种非常高效的编写函数的方法
例如在vue源码中,就有一个柯里化的经典使用
export function createPatchFunction (backend) { `
let i, j
const cbs = {}
const { modules, nodeOps } = backend
return function patch (oldVnode, vnode, hydrating, removeOnly) {
//...
}
}
-
共享状态(闭包)
-
递归
-
高阶函数
高阶函数,就是把函数当参数,把传入的函数做一个封装,然后返回这个封装函数,达到更高程度的抽象。
- 函数组合
函数组合是将两个或更多的函数组合成一个新函数或者执行一些计算的过程。例如,在javascript中,组成 f . g (.点代表组成)等价于f(g(x))。在理解软件是如何使用函数式编程构建时,理解函数组合是非常重要的一步
3.说说 React中的setState执行机制
是什么:
一个组件的显示形态可以由数据状态和外部参数所决定,而数据状态就是state
当需要修改里面的值的状态需要通过调用setState来改变,从而达到更新组件内部数据的作用
因为React并不像vue2中调用Object.defineProperty数据响应式或者Vue3调用Proxy监听数据的变化
必须通过setState方法来告知react组件state已经发生了改变
更新类型
在组件生命周期或React合成事件中,setState是异步;
在setTimeout或者原生dom事件中,setState是同步;
异步更新
setState设计为异步,可以显著的提升性能
如果每次调用 setState都进行一次更新,那么意味着render函数会被频繁调用,界面重新渲染,这样同步更新的效率是很低
如果我们知道可能会得到多个更新,最好批量更新
setState是一个伪异步,或者可以称为defer,即延迟执行但本身还在一个事件循环,所以它的执行顺序在同步代码后、异步代码前。为什么会有这种现象?这就要说到react的合成事件了,react的批处理更新也得益于合成事件。
4 说说对React Hooks的理解?解决了什么问题?
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性
在以前,函数组件也被称为无状态的组件,只负责渲染的一些工作
因此,现在的函数组件也可以是有状态的组件,内部也可以维护自身的状态以及做一些逻辑方面的处理
最常见的hooks有如下:
- useState
- useEffect
- useMemo
- useContext
- useReducer
- useRef
...
解决什么
通过对上面的初步认识,可以看到hooks能够更容易解决状态相关的重用的问题:
- 每调用useHook一次都会生成一份独立的状态
- 通过自定义hook能够更好的封装我们的功能
编写hooks为函数式编程,每个功能都包裹在函数中,整体风格更清爽,更优雅
hooks的出现,使函数组件的功能得到了扩充,拥有了类组件相似的功能,在我们日常使用中,使用hooks能够解决大多数问题,并且还拥有代码复用机制,因此优先考虑hooks
5.说说你是如何提高组件的渲染效率的?在React中如何避免不必要的render
是什么:
react 基于虚拟 DOM 和高效 Diff算法的完美配合,实现了对 DOM最小粒度的更新,大多数情况下,React对 DOM的渲染效率足以我们的业务日常
复杂业务场景下,性能问题依然会困扰我们。此时需要采取一些措施来提升运行性能,避免不必要的渲染则是业务中常见的优化手段之一
如何做
在之前文章中,我们了解到render的触发时机,简单来讲就是类组件通过调用setState方法, 就会导致render,父组件一旦发生render渲染,子组件一定也会执行render渲染
从上面可以看到,父组件渲染导致子组件渲染,子组件并没有发生任何改变,这时候就可以从避免无谓的渲染,具体实现的方式有如下:
shouldComponentUpdate
PureComponent
React.memo
useMemo
useCallbck
- shouldComponentUpdate(nextProps, nextState)
通过shouldComponentUpdate生命周期函数来比对 state和 props,确定是否要重新渲染
默认情况下返回true表示重新渲染,如果不希望组件重新渲染,返回 false 即可
- React.PureComponent
跟shouldComponentUpdate原理基本一致,通过对 props 和 state的浅比较结果来实现
- React.memo
第一个参数为纯函数的组件,第二个参数用于对比props控制是否刷新,与shouldComponentUpdate()功能类似
React.memo用来缓存组件的渲染,避免不必要的更新,其实也是一个高阶组件,与 PureComponent 十分类似。但不同的是, React.memo 只能用于函数组件
- useCallback
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· 单线程的Redis速度为什么快?
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码