2023.04.17面试题整理--React

157 阅读14分钟

react

1.说说redux的基本流程和核心概念

Redux 的核心概念包括 store、action、reducer 和 middleware。

Store:存储应用程序的状态。它是一个对象,包含了整个应用程序的状态树。它提供了 getState() 方法来获取当前状态,提供了 dispatch() 方法来触发状态变更,还可以通过 subscribe() 方法来监听状态变更事件。
Action:描述发生了什么事情。它是一个普通的 JavaScript 对象,包含了一个 type 属性和一些其他的数据,用于描述应用程序状态的变化。
Reducer:指定了应用程序状态的变化如何响应 actions。它是一个纯函数,接收旧的应用程序状态和一个 action,返回新的应用程序状态。它通常使用 switch 语句根据 action 的 type 属性来处理不同的情况。
Middleware:提供了在发起 action 和 reducer 之间执行额外代码的能力。它是一个函数,可以访问 action 和 store,并且可以使用 next() 方法将 action 传递给下一个 middleware 或 reducer。
Redux 的基本流程如下:

定义应用程序的状态树结构,并创建一个 store 对象来存储状态。
当用户执行某些操作时,创建一个 action 对象来描述这个操作。
将 action 传递给 store.dispatch() 方法,触发 reducer 处理这个 action。
reducer 根据 action 的 type 属性和旧的应用程序状态,返回一个新的应用程序状态。
store 更新自己的状态,并且通知所有订阅了它的组件,使它们能够更新自己的视图。
在实际应用中,通常需要使用一些辅助工具,如 React-Redux 来简化和优化 Redux 的使用。

2.说说react-router的原理

React Router的原理主要是通过监听URL的变化,根据URL匹配到对应的路由规则,然后渲染对应的组件。React Router的核心概念包括RouteLinkSwitchBrowserRouterRouteComponentProps等。

Route组件是React Router中最基本的组件,用于匹配URL路径和对应的组件,它可以通过exact、path、component等属性来配置。Link组件则用于创建指向不同路径的超链接,可以让用户进行页面跳转。Switch组件则用于只渲染第一个匹配到的Route组件,避免重复渲染。

BrowserRouter组件则是用于包裹整个应用的顶层组件,它负责监听浏览器URL变化并更新路由信息。RouteComponentProps则是React Router中的另一个重要概念,它是一个包含路由信息的props对象,可以让组件获取到当前路由的相关信息,如路由参数、查询参数等。

总体来说,React Router的原理就是通过监听URL变化并根据路由规则渲染对应的组件,从而实现前端路由的功能。同时,React Router提供了一系列基本组件和API,方便我们进行路由的配置和管理。

3.react中diff的原理

在React中,Diff算法是一种用于优化组件渲染的算法,它通过比较新旧两个虚拟DOM树的差异,最小化DOM操作的次数,从而提高了组件的渲染性能。

React中的Diff算法基于以下几个原则:

两个不同类型的元素会产生不同的树形结构。

开发者可以通过key属性来暗示哪些子元素在不同的渲染下能保持稳定。

React会对同一层级的同类元素进行比较,并且会尽可能地复用相同的DOM节点。

在进行Diff算法时,React会首先比较两个虚拟DOM树的根节点,如果节点类型不同,则直接替换整个节点。如果节点类型相同,则比较节点的属性和子节点。

在比较子节点时,React会先比较新旧两个虚拟DOM树的子节点的key值,如果key值相同,则说明这是同一个节点,React会复用旧的节点并更新它的属性。如果key值不同,则说明这是不同的节点,React会删除旧的节点并创建新的节点。

如果新的虚拟DOM树比旧的虚拟DOM树多了一些节点,则React会将这些新节点插入到旧节点之后;如果新的虚拟DOM树比旧的虚拟DOM树少了一些节点,则React会将这些多余的旧节点删除。

需要注意的是,Diff算法并不是完美的,它可能会出现一些性能问题。例如,如果虚拟DOM树比较复杂,Diff算法的时间复杂度可能会很高,导致组件的渲染性能下降。

4.react中setState的原理

React中,setState是一种用于更新组件状态的方法。它是异步的,也就是说,调用setState并不会立即更新组件状态,而是放到一个队列中,等到合适的时机才会更新组件状态。

setState的原理可以概括为以下几个步骤:

合并状态
调用setState时,React会将新的状态对象合并到原来的状态对象中,从而得到一个新的状态对象。

触发更新
React会将新的状态对象放到一个更新队列中,并触发组件的重新渲染。在重新渲染时,React会比较新旧两个虚拟DOM树的差异,最小化DOM操作的次数,从而提高了组件的渲染性能。

执行回调
如果调用setState时传入了回调函数,则会在组件更新完成后执行回调函数。

需要注意的是,由于setState是异步的,因此在调用setState之后,不能立即获取更新后的状态值。如果需要获取更新后的状态值,可以在回调函数中获取,或者使用setState的第二个参数,它是一个可选的回调函数,将在setState完成并且组件已经重新渲染时被调用。

另外,React还提供了一种叫做“函数式更新”的方式,可以用于更新状态依赖于先前状态的情况。在函数式更新中,setState可以接收一个函数作为参数,这个函数会接收先前的状态作为参数,并返回一个新的状态值。例如:

this.setState((prevState) => {
  return {
    count: prevState.count + 1
  };
});
在上述代码中,setState接收一个函数作为参数,这个函数会接收先前的状态作为参数,并返回一个新的状态值。

5.useEffect和useLayoutEffect有什么区别?

useEffect和useLayoutEffect都是ReactHook函数,都可以用来在函数组件中执行副作用操作,如访问DOM、发起网络请求、订阅事件等。它们的区别在于执行时间和优先级。

useEffect会在浏览器渲染完成后异步执行,不会阻塞浏览器的渲染工作,所以它的执行时间会稍晚于useLayoutEffect。useEffect的优先级较低,不会影响页面的布局和绘制。

useLayoutEffect则会在浏览器完成布局和绘制之后同步执行,它的优先级较高,可以在页面更新前同步读取DOM的尺寸和位置等信息,从而避免出现页面闪烁等问题。

总之,如果需要在渲染后执行一些异步操作,可以使用useEffect;如果需要在渲染前同步操作DOM,可以使用useLayoutEffect。

6.diff算法

Diff算法是React中用于优化组件渲染性能的核心算法之一。其主要作用是比较前后两次组件的状态和属性,找出需要更新的部分,避免不必要的渲染,从而提高应用性能。

Diff算法的过程如下:

首先比较组件的根节点,如果根节点类型不同,则直接卸载旧节点,重新渲染新节点;如果根节点类型相同,则继续比较子节点。

然后比较子节点,如果子节点类型不同,则直接卸载旧节点,重新渲染新节点;如果子节点类型相同,则继续比较子节点的属性和状态。

最后比较子节点的属性和状态,如果有变化,则更新对应的DOM节点。

对于子节点的列表,React使用key属性来确定哪些节点需要更新,哪些节点需要添加或删除。

Diff算法的优化策略如下:

尽可能地复用已有的DOM节点,避免重复创建和销毁DOM节点。

将多个更新操作合并为一个操作,减少DOM操作次数。

对于列表中的子节点,使用唯一的key属性来标识节点,以便快速地识别需要更新的节点。

总之,Diff算法是React中用于优化组件渲染性能的核心算法。在实际开发中,需要注意使用合适的key属性、避免不必要的渲染和减少DOM操作次数,从而提高应用性能。

7.usememo和usecallback有什么区别?

useMemo和useCallback都是ReactHook函数,它们的作用都是优化函数组件的性能,避免组件的不必要渲染。它们之间的区别如下:

返回值不同:useMemo返回一个值,而useCallback返回一个函数。

使用场景不同:useMemo用于缓存计算结果,避免重复计算,通常用于处理耗时的计算和大量数据的计算。而useCallback用于缓存函数,避免函数的重复创建,通常用于传递给子组件的回调函数或effect中的依赖项。

传入参数不同:useMemo传入一个函数和一个依赖项数组,只有当依赖项数组中的值发生变化时才会重新计算。而useCallback传入一个函数和一个依赖项数组,只有当依赖项数组中的值发生变化时才会返回一个新的函数。

优化的方式不同:useMemo是通过缓存计算结果来优化性能的,而useCallback是通过缓存函数来优化性能的。

因此,在实际使用中,如果需要缓存计算结果,可以使用useMemo;如果需要缓存函数,可以使用useCallback。但是,需要注意传入的依赖项数组,避免不必要的重新计算和函数的重复创建,从而提高组件的性能。

8.为什么usecallback和usememo过多影响性能

useCallback和useMemo这两个ReactHook函数都是用来优化组件性能的,它们可以避免不必要的渲染,减少组件的计算量,提高应用的性能。但是,过多地使用这两个函数也可能会影响应用性能,原因如下:

过多的依赖项:使用useCallback和useMemo时,需要传入依赖项,当依赖项发生变化时,才会重新计算。如果依赖项过多或者不合理,会导致组件在不必要的情况下重新渲染,从而降低性能。

过度优化:过度地使用useCallback和useMemo可能会使代码变得复杂,增加维护成本,还可能会导致过度优化,从而产生逆向效果。

过度计算:useCallback和useMemo的实现需要消耗一定的计算资源,如果过度使用,会增加计算负担,从而降低性能。特别是在需要计算大量数据或者处理复杂逻辑时,过度使用这两个函数可能会导致性能问题。

因此,在使用useCallback和useMemo时,需要根据具体情况进行权衡和取舍,避免过度使用。在实际开发中,可以结合性能测试工具对应用进行性能优化,找到性能瓶颈并进行优化,从而提高应用的性能。

9.react里的key

React中的key是用来标识组件的唯一性的属性,它主要用于优化组件的渲染性能。Key可以帮助React更加准确地识别哪些组件需要更新,哪些组件需要重新渲染,从而避免不必要的渲染和提高应用性能。

具体来说,当一个列表中的组件需要重新排序或者删除、添加某些项时,React会根据组件的key属性来确定哪些组件需要重新渲染。如果不提供key属性,React会默认使用数组的下标作为key,但是这样可能会导致不必要的渲染和bug,因此在实际开发中,应该为每个组件提供唯一的key属性。

在使用key属性时,需要注意以下几点:

key应该是每个列表项唯一的标识,通常使用字符串或数字作为key。

key应该稳定不变,不应该随着渲染顺序的改变而改变。

key应该在同一列表中具有唯一性,不应该出现重复的key。

总之,key是React中一个重要的属性,它可以帮助我们优化组件的渲染性能,避免不必要的渲染和提高应用性能。在实际开发中,需要注意为每个组件提供唯一的key属性,并确保key的稳定性和唯一性。

10.react如何自定义hooks

React中,自定义Hooks是一种用于封装可重用逻辑的方式,它可以让我们把组件之间共享的逻辑抽离出来,封装成一个可复用的函数。自定义Hooks是一个函数,它的名称应该以use开头,这样React就可以正确地识别它是一个Hook。

自定义Hooks可以使用所有的React Hook,包括useState、useEffect、useContext、useReducer、useCallback、useMemo、useRef和useImperativeHandle等。

以下是一个简单的自定义Hook示例:

import { useState, useEffect } from 'react';

function useDocumentTitle(title) {
  useEffect(() => {
    document.title = title;
  }, [title]);
}

function MyComponent() {
  useDocumentTitle('My Component');
  return <div>My Component</div>;
}
在上述代码中,useDocumentTitle是一个自定义Hook,它接收一个title参数,并在组件渲染时设置document的title。MyComponent组件使用useDocumentTitle Hook来设置组件的标题。

需要注意的是,自定义Hooks必须遵循以下两个规则:

只能在函数组件或者其他自定义Hooks中使用,不能在class组件中使用。

Hook的名称必须以use开头,这样React才能正确地识别它是一个Hook。

通过自定义Hooks,可以将组件之间共享的逻辑抽离出来,提高代码的复用性和可维护性。同时,自定义Hooks也可以使代码更加清晰和简洁,让组件的逻辑更加集中和易于维护。

11.为什么filber是可中断的呢

Fiber之所以是可中断的,是因为它采用了一种时间分片的机制。在React早期的版本中,当组件开始渲染时,会一直执行直到渲染完成,期间无法中断,这样会导致页面卡顿,用户体验不佳。

而Fiber则将组件的渲染过程拆分成多个任务单元,每个任务单元的执行时间不超过16ms,如果超过了16ms,React就会中断当前任务单元的执行,让浏览器先处理其他任务单元,这样就能够避免页面卡顿。

同时,Fiber还提供了优先级调度功能,可以根据任务的优先级来决定任务的执行顺序,从而更加灵活地控制页面的渲染。这样,在用户交互时,React可以优先执行高优先级的任务,提高响应速度,提升用户体验。

因此,Fiber的可中断性是为了提高页面的流畅度和用户体验。

12.有了解过filber吗

FiberReact中一种用于调度和执行组件更新的新的机制。它的出现是为了解决React早期版本中组件渲染过程中可能出现的性能问题,如长时间的任务阻塞、页面卡顿等。

Fiber的核心思想是将组件的渲染过程拆分成多个任务单元,每个任务单元的执行时间不超过16ms,如果超过了16ms,React会中断当前任务单元的执行,让浏览器先处理其他任务单元,这样就能够避免页面卡顿。

同时,Fiber还提供了优先级调度功能,可以根据任务的优先级来决定任务的执行顺序,从而更加灵活地控制页面的渲染。这样,在用户交互时,React可以优先执行高优先级的任务,提高响应速度,提升用户体验。

总之,Fiber的出现是为了提高React的性能和用户体验,它采用了一系列新的机制来优化组件的渲染过程,从而使得React能够更加高效地执行组件更新。