React 前端面试全攻略:基础概念、组件、Hooks 等热门考点详解
一、基础概念
- 什么是 React?
- React 是用于构建用户界面的 JavaScript 库。
- 基于组件化、声明式编程等特点,采用组件化开发方式,代码可维护和可复用性高。
- 使用虚拟 DOM 提高性能,支持服务器端渲染和移动端开发。
- 对 JSX 的理解?
- JSX 是 React 中特有的语法扩展,允许在 JavaScript 代码中编写类似 HTML 的标记。
- 实际上会被转换为 JavaScript 函数调用,最终创建 React 元素,能方便地将界面和逻辑紧密结合。
- 虚拟 DOM 的概念及优势
- 虚拟 DOM 是真实 DOM 的内存表示,是一个 JavaScript 对象。
- 优势包括提高性能(通过 diff 算法找出最小差异进行更新,减少对真实 DOM 的操作)、跨平台(方便在不同环境中使用)等。
二、组件类
- 类组件和函数组件的区别?
- 语法上,类组件需要继承
React.Component
并定义render
方法,而函数组件是一个纯函数接收props
并返回 React 元素。 - 状态管理方面,类组件可以使用
setState
管理内部状态,函数组件在 React 16.8 之前是无状态的,但之后可以使用useState
等 Hooks 管理状态。 - 生命周期方面,类组件有完整的生命周期钩子,函数组件在早期没有,但可以使用
useEffect
等模拟部分生命周期。
- 语法上,类组件需要继承
- PureComponent 和普通 Component 的区别?
PureComponent
会对props
和state
进行浅层比较,如果属性值相同则不会触发重新渲染,而普通Component
需要手动实现shouldComponentUpdate
来进行性能优化判断。- 但
PureComponent
对于复杂数据类型的比较可能存在问题,因为只是浅层比较。
三、状态管理类
- React 中 state 和 props 的区别?
props
是父组件传递给子组件的数据,是只读的,用于组件之间的数据传递。state
是组件内部的状态,用于管理组件自身的数据,可以在组件内部进行修改,并且状态的改变会触发组件的重新渲染。
- 为什么不能直接修改 React 的 state?
- 直接修改
state
不会触发组件的重新渲染,无法正确更新界面。 - 必须使用
setState
方法来更新state
,setState
通过队列机制来合并和更新状态,保证数据的一致性和正确的渲染。
- 直接修改
四、组件通信类
- React 中组件间通信的方式有哪些?
- 父子组件通信:父组件通过
props
向子组件传递数据,子组件通过props
中的回调函数向父组件传递数据。 - 兄弟组件通信:可以通过共同的父组件作为中间件,在父组件中定义状态和方法,让兄弟组件通过父组件进行数据传递;也可以使用状态管理库(如 Redux 或 Context API)进行全局状态管理,实现兄弟组件之间的通信。
- 父子组件通信:父组件通过
- 如何在 React 中实现跨级组件通信?
- 使用 Context API 可以实现跨级组件通信,创建一个
Context
对象,在父组件中提供数据,子组件中通过Context.Consumer
或useContext
Hook 来获取数据。
- 使用 Context API 可以实现跨级组件通信,创建一个
五、生命周期类
- React 16.8+ 的生命周期函数有哪些阶段及各阶段的主要方法?
- 挂载阶段:
constructor
(初始化 state 和绑定方法)、getDerivedStateFromProps
(根据新的props
更新state
)、render
(渲染组件)、componentDidMount
(获取 DOM 节点、发送网络请求等操作)。 - 更新阶段:
getDerivedStateFromProps
、shouldComponentUpdate
(判断是否需要重新渲染组件)、render
、getSnapshotBeforeUpdate
(在更新前获取一些数据)、componentDidUpdate
(组件更新后执行的操作)。 - 卸载阶段:
componentWillUnmount
(清理定时器、取消网络请求等资源释放操作)。
- 挂载阶段:
- React 的异步请求应该放在哪个生命周期中?
- 官方推荐在
componentDidMount
中进行异步请求,因为componentWillMount
在 React 17 之后会被废弃,并且在该生命周期中请求可能会导致服务器渲染时请求两次以及在 React Fiber 重写后可能多次调用等问题。
- 官方推荐在
六、性能优化类
- 如何提高 React 应用的性能?
- 减少计算量(如使用
key
属性优化列表渲染、合并多个state
等)。 - 利用缓存(使用
useMemo
和useCallback
避免不必要的重新计算和渲染)。 - 精确重新计算的范围(只传递子组件需要的
props
、实现优先级更新等)。 - 懒加载(使用
React.lazy
和webpack
的动态导入)。 - 懒渲染(判断组件是否在可视区域内进行渲染)等。
- 减少计算量(如使用
七、Hooks 类
- React Hooks 的使用规则及为什么有这些规则?
- 规则包括只能在函数组件的顶级调用 Hooks,不能在循环、条件判断或嵌套函数中调用。
- 这是因为 Hooks 的实现基于数组,不按规则调用会导致数组取值错位,执行错误的 Hook。
- useEffect 和
componentDidMount
、componentDidUpdate
、componentWillUnmount
的关系?useEffect
结合不同的依赖项数组参数可以模拟componentDidMount
(依赖项数组为空)、componentDidUpdate
(依赖项数组为指定的状态)、componentWillUnmount
(在useEffect
的返回函数中执行清理操作)。
八、路由类(如果使用了 React Router)
- React Router 的实现原理?
- 基于浏览器的路由机制(如
hash
路由和H5 history
路由),通过监听 URL 的变化,根据配置的路由路径匹配对应的组件并进行渲染,同时维护历史记录等。
- 基于浏览器的路由机制(如
- 如何配置 React Router 实现路由切换、重定向、获取 URL 的参数和历史对象?
- 配置路由切换需要使用
<Route>
组件定义路由路径和对应的组件,使用<Switch>
组件进行路由匹配,使用<Link>
或useHistory
等进行导航和路由操作。 - 重定向可以使用
<Redirect>
组件。 - 获取 URL 的参数可以通过
props.match.params
(动态路由参数)、props.location.search
(查询参数)等方式。 - 获取历史对象可以使用
useHistory
Hook 或this.props.history
(在类组件中)。
- 配置路由切换需要使用
九、高阶组件类
- 什么是高阶组件?有什么作用和应用场景?
- 高阶组件是一个函数,接收一个组件作为参数并返回一个新的组件。
- 作用是复用组件逻辑、增强组件功能等。
- 应用场景如对组件进行权限验证、日志记录、数据处理等操作。
十、Refs 类
- Refs 在 React 中的作用是什么?如何使用?
- Refs 提供了一种访问
render
方法中创建的 DOM 节点或 React 元素的方法。 - 可以通过在组件上添加
ref
属性,属性值为回调函数接收底层 DOM 元素或组件实例,或者使用字符串形式的ref
在组件实例的refs
属性中存储对 DOM 元素的引用。 - 常用于获取 DOM 元素的信息、操作 DOM 元素、在表单元素中获取用户输入的值等。
- Refs 提供了一种访问
十一、总结
本文全面总结了 React 前端面试常见问题,涵盖基础概念、组件、状态管理、组件通信、生命周期、性能优化、Hooks、路由、高阶组件和 Refs 等方面。在面试中,除掌握这些知识点外,还需能够实际应用来解决问题。
在 React 的世界里,每一次挑战都是成长的机遇。勇敢面对面试,展现你的实力,相信自己一定能在 React 前端的道路上绽放光彩!