以下面试题摘抄于juejin.cn/post/734997… 部分面试题答案有所整理与更改
1、JSX是什么,它和JS有什么区别
答案: JSX是JavaScript语法的扩展,它允许编写类似于HTML的代码,它可以编译为常规的JavaScript函数调用,从而为创建组件标记提供了一种更好的方法。
2、React事件机制和原生DOM事件流有什么区别
答案: 事件绑定位置:在react 16之前,事件是绑定在document上面的;在react 16后,事件是绑定在root根组件的dom上的,而原生DOM事件绑定是直接绑定在具体的dom元素上的;这意味着,在React中,所有事件都是通过document进行统一处理,然后再由React进行分发和处理;而在原生DOM中,事件是直接绑定到具体的DOM元素上,这样的事件处理更加直接和高效。 事件处理优先级:由于React事件绑定在document上或者root根组件的dom上,而原生DOM事件直接绑定到元素上,因此原生DOM事件的处理优先级高于React事件。这意味着,如果在一个元素上同时注册了React事件和原生DOM事件,当该事件被触发时,原生DOM事件的监听器会先于React事件的监听器执行。 事件对象类型:React的事件对象是合成对象,不是原生的,这表明React事件对象与原生DOM事件对象在结构和属性上可能存在差异。这种差异对于开发者来说意味着在使用React事件时需要遵循React的事件处理机制,而不是直接使用原生DOM事件的API和处理方式。
3、Redux工作原理
答案: redux是react的第三方状态管理库,创建于上下文API存在之前。它基于一个称为 存储 的状态容器的概念,组件可以从容器中作为props接收数据。更新存储区的唯一方法是向存储区发送一个操作,该操作被传递到一个reduce中。reduce接收操作和当前状态,并返回一个新状态,触发订阅的组件重新渲染。
4、React-Router工作原理? react-router-dom有哪些组件
答案: react-router主要由路由组件、路由匹配组件和导航组件组成。其依赖库history提供了不同的历史记录模式,如browserhistory(用于现代web浏览器)、hashhistory(用于旧版浏览器)、memoryhistory(用于非Dom环境)。 react-router-dom提供了三种类型的组件:路由组件、路由匹配组件、导航组件。
-
路由组件:
BrowserRouter和HashRouter。BrowserRouter基于 HTML5 history API (pushState, replaceState, popstate) 事件,而HashRouter基于window.location.hash。
-
路由匹配组件:
Route和Switch。Route组件用于定义路由规则,可以设置component、render、children属性来渲染对应的内容。Switch用于将多个路由组合在一起。
-
导航组件:
Link、NavLink和Redirect。NavLink是特殊的Link组件,当路径匹配时,渲染的<a>标签带有active类。
这些组件的使用使得在 React 应用中实现路由和导航变得简单和直观。在使用这些组件时,需要从 react-router-dom 中引入它们,例如:
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
5、React hooks解决了什么问题? 函数组件与类组件的区别
答案: react hooks 解决了函数组件中管理状态和副作用的一些常见问题。
1、复用状态逻辑困难:类组件通过高阶组件、装饰器等复用状态逻辑,但这些方法不适用于函数组件。
2、难以理解的类组件生命周期(诸如this绑定问题)
3、状态和副作用难以理解和管理,尤其是在大型应用中。
hooks提供额useState,useEffect,useContext等内置钩子,使得函数组件也可以有自己的状态、处理副作用,并且可以轻松复用这些逻辑。
函数组件与类组件的主要区别:
1、类组件有自己的生命周期和状态,而函数组件通过props和context接收数据。
2、类组件状态的更新依赖于this.setState,而函数组件使用react hooks如useState来管理状态。
3、类组件中的this不是由用户控制,而函数组件的this是可选的,通常使用箭头函数以避免this绑定问题。
6、SetState是同步还是异步的,setState做了什么
答案: setState在react可调度范围内(react的合成事件内部调用,如handle click函数内)是异步的,而在react可调度范围外(如setTimeout或其他非react合成事件内部被调用)则是同步的。
在react中,setState是组件中用于更新状态的方法,它接收一个对象或一个函数作为参数。当传递一个对象时,setState会将该对象合并到当前的状态对象中,并触发组件的重新渲染。当传递一个函数时,该函数会接收先前的状态作为参数,并返回一个新的状态对象,然后setstate方法会将返回的状态对象合并到当前的状态中。
在 React 中,setState() 函数不是一调用就马上改变组件 state 的值。比如多次调用 setState() ,它产生的效果会合并起来处理。
当调用 setState 时,React 先把传入的对象和组件现有的状态合并。然后开始“和解”过程,也就是想办法根据新状态高效更新用户界面(UI)。为了做到这点,React 会构建一个新的表示 UI 的对象树(React 元素树)。
有了新树后,为知道 UI 该怎么随新状态变化,React 会把新树和之前的元素树做比较。
打个比方,state 就像一个仓库里货物的清单,setState 是改变清单的指令。React 收到指令不是马上改清单,而是先整理合并这些改变的要求,然后重新规划仓库的布局(构建新元素树),再对比之前的布局看看具体哪些地方要调整(和旧元素树比较)。
7、什么是fiber,fiber解决了什么问题
答案: Fiber是react中的新的更新机制,旨在提高react应用程序的性能和用户体验。具体来说,fiber通过以下方式解决了传统react渲染机制中的性能问题:
- 增量渲染和中断机制:fiber将渲染过程划分为多个小任务,这些任务可以根据浏览器的空闲时间和优先级进行调度。当遇到高优先级的任务时,fiber可以中断当前的渲染任务,从而避免长时间阻塞主线程,提高了页眉的响应性和流畅性。
- 优先级调度:通过为每个任务分配优先级,fiber确保了高优先级的任务可以先于低优先级的任务执行。这种机制使得react能够更好地响应用户的交互,如滚动和点击事件,从而提升了用户体验。
- 错误处理和并发处理:fiber还引入了新的错误处理机制,能够更好地捕获和处理组件中发生的错误。此外,它为react未来支持并发模式奠定了基础,这有助于进一步提高应用程序的性能和响应速度。
总体来说,Fiber通过其独特的增量渲染和中断机制,以及优先级调度策略,显著提高了React应用程序的性能和用户体验,特别是在处理大型组件树或高频更新时。
8、React中在哪捕获错误?
答案: 在React中,可以通过多种方式来捕获错误。以下是几种常见的方法:
- 使用
componentDidCatch和static getDerivedStateFromError方法(Error Boundaries(错误边界))捕获渲染错误和生命周期错误。注意:ErrorBoundaries应该尽可能靠近可能抛出错误的组件,以便尽快捕获错误。 - 使用window.onError 捕获全局错误。
- 使用react.Profiler检测渲染错误
- 使用开发者工具(如redux devtools)来调试和捕获错误
- 使用第三方库(如Sentry)来集中管理错误
9、React组件传值有哪些方式
答案:
- 父传子:props
- 子传父:回调函数、ref
- 兄弟组件通信:状态提升机制、路由跳转传值
- 跨级组件通信:useContext传值、redux共享数据
10、react如何做到和vue中keep-alive的缓存效果
- 使用React的状态管理: 可以使用React的状态(如
useState或useReducer)来存储页面中需要存储的数据。当需要这些数据的时候,不重新加载数据,而是从状态中读取数据。 - 使用React.memo或React.PureComponent,函数组件可以使用
React.memo来防止不必要的重新渲染。对于类组件,可以使用React.PureComponent。保持组件状态,但请注意,这仅当组件的props或state没有变化时才会阻止重新渲染。 - 使用React.createPortal(如果确实需要),
React.createPortal主要用于DOM的渲染位置控制,而不是数据缓存。
11、react如何做路由监听
在React中,可以使用react-router-dom库中的useHistory和useLocation钩子来监听路由的变化。
以下是一个简单的例子,展示如何在React函数组件中监听路由变化:
import React from 'react';
import { useHistory, useLocation } from 'react-router-dom';
function RouteListener() {
const history = useHistory();
const location = useLocation();
React.useEffect(() => {
console.log('路由变化了!', location.pathname);
// 你可以在这里根据路由变化执行一些逻辑
}, [location.pathname]); // 依赖location.pathname来确保只有路由变化时,Effects才会重新执行
return (
<div>
<button onClick={() => history.push('/some-path')}>跳转到some-path</button>
</div>
);
}
export default RouteListener;
在这个例子中,useHistory钩子用于获取历史对象,useLocation钩子用于获取当前位置的信息。useEffect钩子用来监听路由位置的变化,每次路由变化时,都会执行里面的函数。
12.React 中 keys 的作用是什么?
react中的keys主要用于优化DOM渲染性能,确保列表中的元素能够被正确地识别和更新。
- 追踪元素的变化
- 优化渲染性能
- 确保状态唯一性
13.React 中 refs 的作用是什么?
ref允许开发者直接访问组件实例或 DOM 节点.
- 访问dom节点
- 与第三方库集成
- 调用组件方法
14.React diff 原理
react diff算法是react比较两个虚拟dom的差异,并仅应用必要的变化到实际DOM上的高效算法。
- 在进行dom更新时,会将虚拟dom树转换成实际dom
- 当应用状态改变时,react会使用新的状态生产新的虚拟dom树
- react会遍历两颗虚拟dom树,找出他们之间的最小差异,并只应用这些差异到实际DOM上