1、什么是虚拟DOM? 答: 虚拟 DOM 是 React 中的一个概念,其中创建实际 DOM(文档对象模型)的轻量级虚拟表示并将其存储在内存中。它是一种用于优化 Web 应用程序性能的编程技术。
当 React 组件的数据或状态发生更改时,虚拟 DOM 会被更新,而不是直接操作真实 DOM。然后,虚拟 DOM 计算组件的先前状态和更新状态之间的差异,称为“比较”过程。
一旦识别出差异,React 就会高效地仅更新真实 DOM 的必要部分以反映更改。这种方法最大限度地减少了实际 DOM 操作的数量,并提高了应用程序的整体性能。
通过使用虚拟 DOM,React 提供了一种创建动态和交互式用户界面的方法,同时确保最佳效率和渲染速度。
【注:虚拟 DOM: 本质上就是一个 JS 对象, 通过一个对象来描述了每个 DOM 节点的特征, 并且通过虚拟 DOM 就能够完整的绘制出对应真实的 DOM】 虚拟DOM的好处如下: 虚拟 DOM 设计的核心就是用高效的 js 操作, 来减少低性能的 DOM 操作, 以此来提升网页性能, 然后使用 diff 算法对比新旧虚拟 DOM, 针对差异之处进行重新构建更新视图, 以此来提高页面性能, 虚拟 DOM 这让我们更关注我们的业务逻辑而非 DOM 操作, 这一点即可大大提升我们的开发效率
虚拟DOM缺点: 极致性能: 在一些性能要求极高的应用中, 虚拟 DOM 无法进行针对性的极致优化: 因为从虚拟 DOM 到更新真实 DOM 之间还需要进行一些额外的计算(比如 diff 算法), 而这中间就多了一些消耗, 肯定没有直接操作 DOM 来得快
首次渲染: 首次渲染大量 DOM 时, 需要将虚拟树转换为实际的 DOM 元素, 并插入到页面中, 这个过程需要额外的计算和操作, 可能会比直接操作实际 DOM 更慢
适用度: 虚拟 DOM 需要在内存中创建和维护一个额外的虚拟树结构, 用于表示页面的状态。这可能会导致一定的内存消耗增加, 特别是在处理大型或复杂的应用程序时, 所以虚拟 DOM 更适用于动态或频繁变化的内容, 而对于静态内容 (几乎不会变化的部分), 虚拟 DOM 的优势可能不明显, 因为它仍然需要进行比较和更新的计算
2、什么是JSX? 答: JSX 是 JavaScript 语法的扩展,它允许编写类似于 HTML 的代码。它可以编译为常规的 JavaScript 函数调用,从而为创建组件标记提供了一种更好的方法。栗子: JSX代码:
3、react使用什么方法可以访问子组件的方法和使用? 答: 中如何实现父组件调用子组件的方法
- 使用Refs调用子组件的方法
- 使用回调函数调用子组件的方法
- 使用上下文(Context)调用子组件的方法
4、数组list[1,2,3,4,5,4,5,6]去重? 答: 双循环去重:双重for(或while)循环是比较笨拙的方法,它实现的原理很简单:先定义一个包含原始数组第一个元素的数组,然后遍历原始数组,将原始数组中的每个元素与新数组中的每个元素进行比对,如果不重复则添加到新数组中,最后返回新数组
indexOf方法去重: 数组的indexOf()方法可返回某个指定的元素在数组中首次出现的位置。该方法首先定义一个空数组res,然后调用indexOf方法对原来的数组进行遍历判断,如果元素不在res中,则将其push进res中,最后将res返回即可获得去重的数组
相邻元素去重: 这种方法首先调用了数组的排序方法sort(),然后根据排序后的结果进行遍历及相邻元素比对,如果相等则跳过改元素,直到遍历结束
利用对象属性去重: 创建空对象,遍历数组,将数组中的值设为对象的属性,并给该属性赋初始值1,每出现一次,对应的属性值增加1,这样,属性值对应的就是该元素出现的次数了
set与解构赋值去重【[...new Set(arr)]】: ES6中新增了数据类型set,set的一个最大的特点就是数据不重复。Set函数可以接受一个数组(或类数组对象)作为参数来初始化,利用该特性也能做到给数组去重
Array.from与set去重【Array.from(new Set(arr))】: Array.from方法可以将Set结构转换为数组结果,而我们知道set结果是不重复的数据集,因此能够达到去重的目的
总结: 数组去重是开发中经常会碰到的一个热点问题。我们可以根据不同的应用场景来选择不同的实现方式。
5、对象数组list{value:1},{value:1},{value:1},{value:2},{value:2}去重,获取唯一id? 答:
6、说下react有哪两种组件,它们的优缺点有哪些? 答: React 函数式组件和类组件的主要区别在于它们的定义方式和所拥有的特性。 定义方式: 函数式组件:是以一个纯 JavaScript 函数作为组件,这个函数接收 props 作为参数并返回一个 React 元素。 function Welcome(props) { return
Hello, {props.name}
; }类组件:是使用 ES6 类和 React 的 Component 基类创建的。 class Welcome extends React.Component { render() { return
Hello, {this.props.name}
; } }状态(State): 函数式组件是无状态的,意味着它们不能有自己的状态。每次父组件更新时,函数式组件都会接收新的 props。 类组件有自己的内部状态,通过 this.state 访问,并且可以使用生命周期方法和状态更新机制。
生命周期方法: 函数式组件没有自己的生命周期,因为它们就是函数。 类组件有完整的生命周期方法,如 componentDidMount 和 componentWillUnmount,可以管理时间器、DOM 的引用等。
性能优化: 函数式组件会在其依赖的 props 或 context 发生变化时重新执行。React 会比较前后两个版本的函数式组件的输出(React 元素),并且只会将变化的部分应用到真实的 DOM 操作。 类组件则需要实现 shouldComponentUpdate 方法来进行性能优化,返回 false 可以阻止不必要的重渲染。
高阶组件(Higher-Order Components): 函数式组件可以用高阶组件封装,但类组件不能。 Hooks(React 16.8+): Hooks 让函数式组件也可以使用 state 以及其他的 React 特性,无需变成类组件。
7、编写一个函数,返回的是数组,随机数。。。? 答: 8、react生命周期? 答: React组件的生命周期可以分为三个阶段:
初始化阶段:当组件实例被创建并挂载到DOM中时,会执行这些生命周期方法。 constructor(构建函数) static getDerivedStateFromProps(派生【props】) render(开始渲染组件) componentDidMount(组件渲染完成)
更新阶段:当组件的props或state发生变化时,会执行这些生命周期方法。 static getDerivedStateFromProps(派生【props】) shouldComponentUpdate(组件是否渲染) render(渲染组件) getSnapshotBeforeUpdate(获取快照【更新前的操作状态】) componentDidUpdate(组件更新完成)
卸载阶段:当组件从DOM中卸载时,会执行这个生命周期方法。 componentWillUnmount(组件将要卸载)
9、有使用过hook吗?常用的hooks有哪些? 答: useState:用于管理功能组件中的状态。 useEffect:用于在功能组件中执行副作用,例如获取数据或订阅事件。 useContext:用于访问功能组件内的 React 上下文的值。 useRef:用于创建对跨渲染持续存在的元素或值的可变引用。 useCallback:用于记忆函数以防止不必要的重新渲染。 useMemo:用于记忆值,通过缓存昂贵的计算来提高性能。 useReducer:用于通过reducer函数管理状态,类似于Redux的工作原理。 useLayoutEffect:与useEffect类似,但效果在所有DOM突变后同步运行。
10、react的高阶组件是什么?什么情况下使用? 答: 高阶组件(HOC)是一种函数,接受一个组件作为参数,并返回一个新的组件。这个新的组件具有一些增强的特性或功能。简而言之,高阶组件就是用来“包装”其他组件的函数。 高阶组件的作用: 高阶组件在React开发中有多种作用,主要包括以下几点:
- 代码复用: 高阶组件可以将通用的逻辑抽象出来,使多个组件共享同一段逻辑代码。这样可以减少重复编写相似代码的情况,提高代码的复用性。
- 功能增强: 通过高阶组件,我们可以为组件添加额外的功能,如数据获取、认证、日志记录等。这种方式可以将核心功能与增强功能分开,使代码更加清晰。
- 状态管理: 高阶组件可以帮助组件共享状态,比如将一些全局的状态传递给多个组件,从而实现状态的共享和管理。
- 条件渲染: 高阶组件可以基于一些条件来控制组件的渲染,从而实现动态的组件呈现方式。 跨平台适配: 高阶组件可以用于实现组件在不同平台或环境中的适配。通过创建针对特定平台的高阶组件,可以在不同平台之间共享代码,并根据不同的平台特性进行定制化逻辑
11、类组件和函数组件有什么区别? 定义方式不同,前者是通过es6类和react poc几类创建 后者是存js函数实现 状态不同,前端通过this.state,后者是通过peopes 答: 12、过度使用redux会产生什么后果? 答: 优点: 可预测的状态管理:Redux 提供了一种单一数据源和纯函数操作这个数据源的模式,使得状态管理更加可控和可预测。 方便的调试和测试:由于 Redux 的状态变化是通过纯函数来操作的,因此非常容易进行调试和测试。 适用于大型应用:Redux 适用于复杂的、大型的应用程序,可以帮助开发者更好地组织和管理状态。 缺点: 繁琐的样板代码:使用 Redux 通常需要编写大量的样板代码,尤其是在处理异步操作和副作用时。 学习成本高:Redux 的概念相对抽象,需要一定的学习成本。 过度使用可能导致复杂性增加:在小型应用中过度使用 Redux 可能会导致代码复杂度增加,反而不利于开发。 三大原则: 单一数据源:整个应用的状态被存储在一个单一的对象树中,这使得状态管理变得简单且可维护。 状态是只读的:唯一改变状态的方法是发起一个 action,一个描述发生了什么的普通对象。 纯函数来执行修改:为了描述 action 如何改变状态树,你需要编写 reducers
13、说下redux的中间件? 答: 供的基础服务(功能),衔接⽹络上应⽤系统的各个部分或不同的应⽤,能够达到资源共 享、功能共享的⽬的那么如果需要⽀持异步操作,或者⽀持错误处理、⽇志监控,这个过 程就可以⽤上中间件Redux 中,中间件就是放在就是在 dispatch 过程,在分发 action 进⾏拦截处理。其本质上⼀个函数,对 store.dispatch ⽅法进⾏了改造,在发出 Action 和执⾏ Reducer 这两步之间,添加了其他功能。 有很多优秀的 redux 中间件,如: redux-thunk:⽤于异步操作。接收两个参数dispatch、getState redux-sage: 主要用于处理action中涉及到的一些副作用,来确保reducer始终都是一个纯函数。 redux-logger:⽤于⽇志记录
14、除了redux还有哪些可以实现全局状态的? 答: MobX:MobX 是一个简单、可扩展的状态管理库,它采用响应式编程模型来管理应用的状态。MobX 的核心理念是让状态变化驱动 UI 的更新,而不是通过派发和监听事件来管理状态。MobX 提供了一个装饰器语法,可以很方便地将状态和行为绑定到 React 组件上。
Recoil:Recoil 是 Facebook 推出的一个状态管理库,它基于原子状态的概念来管理应用的状态。Recoil 的主要特点是可以轻松地共享状态、组合状态以及异步加载状态,同时提供了很好的性能优化机制,能够有效地减少不必要的 UI 渲染。
Zustand:Zustand 是一个轻量级的状态管理库,它采用函数式编程的方式来管理应用的状态。Zustand 提供了一个简单的 API,可以帮助开发者轻松地创建和组合状态,并且能够很好地处理异步操作和副作用。
Easy Peasy:Easy Peasy 是一个基于 Redux 的状态管理库,它提供了简单、轻量级的 API 来管理应用的状态。Easy Peasy 可以很方便地集成到 React 应用中,并且支持使用 Hooks 来访问和修改状态。
XState:XState 是一个基于有限状态机的状态管理库,它提供了强大的状态机工具和 API,可以帮助开发者建立状态机模型来管理复杂的应用逻辑。XState 支持定义状态、事件和转换规则,还提供了可视化工具来帮助开发者理解和调试状态机模型。
15、说下hook的好处?使用hook需要注意什么? 答: 优点: 更简洁: 相比于传统的 class 组件, 使用 Hooks 可以将组件的逻辑拆分成更小, 这使得组件代码更加简洁、易读、好维护
易上手: 使用 Hooks 你可以在函数组件中使用状态和其他 React 特性, 无需编写 class 从而避免了繁琐的 class 组件的声明和继承、同时也无需考虑 this 指向等问题
逻辑复用: 自定义 Hooks 允许将组件之间的状态逻辑进行抽离, 作为一个独立的可组合和可共享单元, 从而减少了重复代码的出现
更好的可测试性: 通过 Hooks 可以将组件渲染、和业务逻辑分离进行分离, 使得组件的测试变得更加容易。可以针对每个 Hook 编写单独的测试,确保其正确性, 同时保持组件测试的简洁性。
灵活性: Hooks 的设计允许你在组件内部使用多个不同的 Hook, 这使得你可以在一个函数组件中使用各种各样的特性, 而不必担心组件层次的嵌套和复杂性
有助于代码拆分: 使用 Hooks 可以更容易地拆分组件, 将组件的不同部分拆分成更小的逻辑单元,有助于更好地组织和管理代码。
类组件在业务不断扩展的情况下, 容易变得臃肿难以维护, 往往相关的业务被拆分到多个生命周期里, 或者一个生命周期中存在多个不相关的业务, 而 Hook 的出现, 可以将业务拆分为更小的函数, 对业务逻辑进行更为细腻的控制, 使得组件更容易理解、维护
【补充: 类组件中如果需要复用状态逻辑, 只能通过高阶组件来实现, 没有 hooks 简洁, 而且还多了一层组件嵌套】
缺点: 陡峭的学习曲线: 对于那些熟悉传统 class 组件的开发者来说, 学习 Hooks 可能需要一些时间。Hooks 改变了组件的编写方式, 并且需要理解如何正确地使用 useState、useEffect、useContext 等钩子函数
使用规则: Hooks 有一些使用规则, 例如在条件语句中不可使用, 或者只能在函数组件的最顶层使用。违反这些规则可能导致 bug 和意想不到的行为。
性能问题: 尽管 Hooks 通常可以优化组件逻辑, 但不正确地使用它们可能导致性能问题。比如, 在 useEffect 中没有正确处理依赖项数组可能会导致不必要的重复执行。
【怎么避免 hooks 的常见问题:】 不要在 useEffect 里面写太多的依赖项, 划分这些依赖项成多个单一功能的 useEffect 其实这点是遵循了软件设计的 单一职责模式
拆分组件, 细化组件的粒度, 复杂业务场景中使用 hooks 应尽可能地细分组件, 使得组件的功能尽可能单一, 这样的 hooks 组件更好维护
能通过事件触发数据更新, 就尽量通过事件方式去实现, 尽量避免在 useEffect 中依赖 A 状态然后去修改 B 状态
16、介绍下redux? 答: 一、什么是Redux? Redux是一个JavaScript状态管理库,用于管理应用中的状态(state)。它通过将应用的状态集中存储在一个单一的状态树中,以及通过不可变的方式来更新状态,来解决状态管理的复杂性。Redux遵循一种严格的数据流模式,使得状态的变化可预测且易于调试。
二、Redux的工作原理 Redux的工作原理可以概括为以下几个关键概念:
-
Store: Redux应用的状态被统一地存储在一个称为“store”的对象中。该对象包含了整个应用的状态树。
-
Action: Action是一个包含有关操作的信息的普通对象。它描述了要在应用中执行的操作。例如,当用户点击按钮时,可以创建一个对应的Action。
-
Reducer: Reducer是一个纯函数,它接收当前的状态和一个Action作为参数,并返回一个新的状态。Reducer定义了状态的变化逻辑。
-
Dispatch: Dispatch是一个函数,用于将Action发送给Reducer以更新状态。通过调用dispatch(action),Redux会根据Action的类型找到对应的Reducer来更新状态。
-
Subscribe: 通过订阅(subscribe),可以监听状态的变化。每当状态发生变化时,订阅的回调函数会被触发。
-
Action Creators: Action Creators是一个函数,用于创建并返回Action对象。它可以帮助减少重复的代码,并更好地组织Action。
三、Redux在前端开发中的应用 Redux在前端开发中的应用非常广泛,特别是在大型应用中。它的优点在于:
-
单一数据源: Redux的整个应用状态存储在一个单一的状态树中,使得状态变化易于追踪和管理。
-
可预测性的状态管理: Redux的状态变化是通过纯函数来执行的,保证了状态的变化是可预测的。
-
易于调试: Redux的严格数据流模式以及时间旅行调试工具(DevTools)使得调试变得更加容易。
-
易于共享状态: Redux可以让不同组件之间共享状态变得简单。通过连接(connect)React组件和Redux,可以将状态传递给组件的props。
17、react和vue的区别? 答: React 和 Vue 是当前比较流行的前端框架,它们在技术层面有以下区别: 组件化方式不同:React 是基于组件实现的,组件包含了状态和行为,所有组件共享一个状态树。Vue 也是基于组件实现的,但是每个组件都有自己的状态,并且可以很容易地将数据和行为绑定在一起。
数据驱动方式不同:React 使用单向数据流来管理数据,即从父组件到子组件的传递,所以 React 中组件之间的数据交互相对更加复杂。Vue 则使用双向数据绑定来管理数据,使得组件之间的数据交互更加简洁。
模板语法不同:React 使用 JSX 语法,将 HTML 和 JavaScript 结合在一起,使得编写组件更加直观和灵活。Vue 则使用模板语法,并且支持模板内的表达式和指令,使得编写组件具有更高的可读性和可维护性。
生命周期不同:React 组件的生命周期分为三个阶段:初始化、更新和卸载。Vue 组件的生命周期分为八个阶段:创建、挂载、更新、销毁等。
状态管理方式不同:React 使用 Redux 或者 MobX 来管理应用程序的状态。Vue 则提供了自己的状态管理库 Vuex,可以更方便地管理组件之间的共享状态。
性能优化方式不同:React 使用虚拟 DOM 技术来实现高效的渲染性能,可以减少每次渲染时需要操作真实 DOM 的次数。Vue 则使用模板编译和响应式系统来实现高效的渲染性能,并且还提供了一些优化技术,例如懒加载和缓存等。
【开发人员可以根据项目需求和个人喜好选择合适的框架。】
18、说下react原理? 答:React的原理主要基于虚拟DOM、组件化以及响应式更新机制。以下是React原理的详细解释: 虚拟DOM(Virtual DOM): React内部使用虚拟DOM来优化真实DOM的更新操作。当组件的状态或属性发生变化时,React不会直接操作真实的DOM树,而是创建一棵虚拟DOM树,这棵树是对真实DOM的抽象表示。 React通过比较新旧两棵虚拟DOM树,找出差异,并只将这些差异应用到真实的DOM上。这种方式大大减少了不必要的DOM操作,提高了页面渲染的性能。 组件化(Componentization): React采用组件化的开发方式,将UI拆分成独立的、可复用的组件。每个组件都有自己的状态和行为,并可以通过组合其他组件来构建复杂的UI。 组件化的开发方式提高了代码的可维护性和复用性,使得开发者能够更高效地构建大型应用程序。 响应式更新机制: React实现了响应式的数据流。当组件的状态或属性发生变化时,React会自动触发组件的重新渲染过程。 这个过程是通过React的渲染函数(render method)和生命周期方法(如componentDidUpdate)来实现的。渲染函数负责根据组件的状态和属性生成虚拟DOM树,而生命周期方法则提供了在组件不同生命周期阶段执行自定义逻辑的机会。 React的响应式更新机制保证了UI始终与组件的状态保持一致,并且能够在状态变化时高效地更新UI。 JSX: React使用JSX(JavaScript XML)作为模板语言,使得开发者能够以类似于HTML的语法来描述UI结构。 JSX在编译时会被转换为JavaScript对象,这使得React能够在JavaScript环境下高效地处理UI渲染和更新。
19、element ui怎么实现主题? 答: 20、react 19有什么特性 答: 21、react 18新特性? 答: Automatic batching 自动批处理优化: 批处理: React将多个状态更新分组到一个重新渲染中以获得更好的性能。(将多次 setstate 事件合并) startTransition: 可以用来降低渲染优先级。分别用来包裹计算量大的 function和 value,降低优先级,减少重复渲染次数。 SSR下的 Suspense 组件: Suspense 的作用: 划分页面中需要并发渲染的部分。 hydration[水化]:ssr 时服务器输出的是字符串(html),客户端(一般是浏览器)根据这些字符串并结合加载的 JavaScript 来完成 React 的初始化工作这一阶段为水化。
22、说下自定义组件怎么实现的?自定义组件拓展antd已有属性 答:两大原则: 一、不结合具体业务逻辑:1.子组件只做为数据的容器,数据统一由父组件传入。2.只编写UI逻辑具体的数据操作怎么样的业务逻辑,触发父组件的监听交给父组件处理 二、尽量的提供简便: 1.在不结合具体业务逻辑的前提下,让父组件使用组件时候尽可能方便,原则:通过观察大部分页面设计,能很方便满足大多数页面的需求,少数页面有差距,也有提供扩展方案
23、介绍下ts泛型,怎么定义使用 答:函数中使用 使用方式类似于函数传参,传什么数据类型,T就表示什么数据类型,T也可以换成任意字符串 function identity (arg:T):T{ console.log(arg); return arg; } identity(24);// 返回值是number类型的 24 identity<string | boolean>('identity')//返回值是string类型的 identity identity<string | boolean>(false);//返回值是布尔类型的 false
24、说下虚拟列表的实现原理
25、如果不用虚拟列表应该怎么实现大数据加载
26、说下图片懒加载的原理 答: 图片懒加载的原理方法 1.初始化时,图片标签的src不能是真实的图片地址,也不可以是空地址或者坏地址(会出现图片加载失败的图标)。 2.初始化的时候,可以设置图片的src是某一个小型图片。例如一张1px*1px的透明图片。由于所有图片都使用这一张图片,只会发送一次请求,不会增加性能负担。将图片的真实路径绑定给一个自定义属性,例如data-url。注意:页面的img元素,如果没有src属性,浏览器就不会发出请求去下载图片 3.定义滚动事件,判断元素进入视口,则将src替换为真正的url地址。利用js提取data-url的真实图片地址赋值给src属性
27、说下代码压缩,图片懒加载、资源合并 答:gZip插件配置webpack进行压缩代码 通常使用Webpack作为打包工具资源合并。以下是一个简单的Webpack配置示例,用于将React项目中的多个JavaScript文件以及相关资源(如CSS、图片等)合并为少数几个打包后的文件,从而提高页面加载性能:
28、怎么实现路由拦截,不依赖后段的话前端应该怎么做路由拦截 答: 29、富文本自定义文本链接 30、说下高阶组件的优缺点 31、有自己写过HOC【高阶组件】吗? 32、有使用过哪些性能分析功能,根据哪些工具上哪些节点得出性能问题?
1 是否用过history模式开发项目? 2 有没有使用过react hook?
3 有没有做过Edge Safari 兼容? React 应用在 Edge Safari 浏览器上的兼容性问题可能源于多个因素,包括浏览器对 JavaScript 或 CSS 特性的支持程度、浏览器特有的默认样式差异、事件处理方式的差异等。 为了解决这些兼容性问题,可以采取以下措施: 使用 polyfills:对于不被 Edge Safari 支持的 JavaScript 特性,可以使用第三方库如 core-js 或 babel-polyfill 来提供兼容性支持。 特性检测:使用 caniuse 或类似的服务来识别你的应用可能使用的特性是否在目标浏览器上受支持。 CSS 前缀:为了确保 CSS 特性在不同浏览器上的一致性,可以使用自动化工具如 Autoprefixer。 事件监听和特性检测:针对不同的浏览器,使用条件判断来调整事件监听器的行为或特性。 使用 CSS-in-JS 库:如 styled-components 或 emotion,可以在组件级别编写浏览器兼容的 CSS。 使用 React 提供的生命周期方法:确保使用的是 componentDidMount 和 componentWillUnmount 等React推荐的生命周期方法,而不是 useEffect 中的清理函数来处理卸载逻辑。 测试:在不同的浏览器上进行充分的测试,确保在 Edge Safari 上的表现符合预期。
4 有没有做过权限管理?
5 有没有封装过组件?
6 是否有做过移动端项目?
7 实际在项目中使用过React Native么?
8 最近两年使用的是react还是vue3呢?
9 是否独立负责过项目?