react 面试题(手把手讲解)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

前言

在前端开发领域,React 作为主流框架之一,一直是面试中高频考察的技术点。无论是前端初级工程师还是中级开发者,掌握 React 核心概念、组件通信机制和性能优化技巧,都是应对面试的关键。本文将围绕 “React 面试题” 这一主题,从基础到进阶,结合实际案例和代码示例,帮助读者系统梳理常见问题,并通过形象的比喻加深理解,最终提升面试竞争力。


一、React 核心概念与基础面试题

1.1 什么是 React?

React 是由 Facebook 开发的声明式 JavaScript 库,主要用于构建用户界面。它采用组件化设计,将 UI 拆分为可复用的组件,并通过 虚拟 DOM(Virtual DOM) 实现高效更新。
比喻:可以将 React 比作乐高积木,每个组件就像一块积木,通过组合和嵌套构建复杂的界面,而虚拟 DOM 则像一个“智能助手”,负责计算并优化真实 DOM 的更新。

1.2 虚拟 DOM 是如何工作的?

虚拟 DOM 是 React 的核心机制之一,其工作流程如下:

  1. 创建虚拟节点:将 UI 转换为轻量级的 JavaScript 对象树。
  2. 计算差异(Diffing):对比新旧虚拟 DOM 树的差异,确定需要更新的部分。
  3. 批量更新真实 DOM:仅对差异部分进行渲染,减少直接操作 DOM 的性能损耗。
    代码示例
// 示例:修改状态后触发虚拟 DOM 更新  
class Counter extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = { count: 0 };  
  }  
  increment = () => {  
    this.setState({ count: this.state.count + 1 }); // 触发虚拟 DOM 更新  
  };  
  render() {  
    return (  
      <div>  
        <p>Count: {this.state.count}</p>  
        <button onClick={this.increment}>+1</button>  
      </div>  
    );  
  }  
}  

1.3 类组件与函数组件的区别

  • 类组件(Class Component):基于 ES6 类,需继承 React.Component,支持 state生命周期方法
  • 函数组件(Functional Component):纯函数形式,通过 props 接收数据,结合 Hooks(如 useStateuseEffect)实现状态管理。
    面试考察点:通常会要求对比两者的优缺点,例如函数组件更简洁,而类组件适合复杂逻辑。

二、组件通信与状态管理

2.1 父组件向子组件传递数据

父组件通过 props 将数据传递给子组件,子组件通过 props 接收。
案例:父组件控制子组件的显示内容。

// 父组件  
function Parent() {  
  const [message, setMessage] = useState("Hello");  
  return <Child message={message} />;  
}  

// 子组件  
function Child({ message }) {  
  return <div>{message}</div>; // 通过 props 获取数据  
}  

2.2 子组件向父组件传递数据

通过 回调函数作为 props 实现数据反向流动。
案例:子组件触发父组件状态更新。

// 父组件  
function Parent() {  
  const [count, setCount] = useState(0);  
  const handleIncrement = () => setCount(count + 1);  
  return (  
    <Child onIncrement={handleIncrement} />  
  );  
}  

// 子组件  
function Child({ onIncrement }) {  
  return <button onClick={onIncrement}>+1</button>;  
}  

2.3 跨级组件通信:Context API

当组件层级较深时,使用 Context API 避免“属性钻取”(Prop Drilling)。
步骤

  1. 创建 Context:const MyContext = React.createContext(initialValue);
  2. 提供数据:通过 <MyContext.Provider value={data}> 包裹子组件。
  3. 消费数据:通过 useContext(MyContext)Consumer 获取。
    代码示例
// 创建 Context  
const ThemeContext = React.createContext();  

// 提供者组件  
function ThemeProvider({ children }) {  
  const theme = { color: "blue" };  
  return (  
    <ThemeContext.Provider value={theme}>  
      {children}  
    </ThemeContext.Provider>  
  );  
}  

// 消费组件  
function DisplayTheme() {  
  const theme = useContext(ThemeContext);  
  return <div style={{ color: theme.color }}>主题颜色</div>;  
}  

三、React 生命周期与 Hook 机制

3.1 类组件的生命周期方法

React 16.x 版本前的生命周期方法分为三个阶段:
| 阶段 | 方法 | 作用 |
|------|------|------|
| 挂载阶段 | constructor() | 初始化状态 |
| componentDidMount() | 组件首次渲染完成后执行 |
| 更新阶段 | componentDidUpdate() | 状态/属性更新后执行(首次不触发) |
| 卸载阶段 | componentWillUnmount() | 组件销毁前清理资源 |

比喻:生命周期如同人的成长阶段,从出生(挂载)到成长(更新)再到结束(卸载)。

3.2 React Hook 的核心 API

Hooks 允许函数组件拥有状态和生命周期功能,常见 Hook 包括:

  • useState:管理组件内部状态。
  • useEffect:处理副作用(如数据请求、订阅)。
  • useContext:消费 Context 数据。
    面试高频问题

QuseEffect 的第二个参数 dependencies 是什么作用?
A:控制副作用触发的条件,空数组 [] 表示仅在挂载和卸载时执行。


四、性能优化与常见陷阱

4.1 避免不必要的渲染

  • 使用 React.memo:包装组件,防止无状态变化时重复渲染。
  • Memoization:通过 useMemouseCallback 缓存计算结果或函数。
    代码示例
// 使用 React.memo 阻止子组件重复渲染  
const MemoizedChild = React.memo(({ data }) => {  
  console.log("Child rendered"); // 仅在 data 变化时触发  
  return <div>{data}</div>;  
});  

4.2 关键渲染性能问题

  • 问题:直接修改状态对象(如 this.state.items = [...items])会绕过 React 的状态更新机制,导致组件不更新。
  • 解决方案:使用 setState 并返回新对象,例如:
    this.setState(prevState => ({  
      items: [...prevState.items, newItem]  
    }));  
    

五、进阶知识点与高频面试场景

5.1 高阶组件(HOC)

HOC 是一个接受组件并返回新组件的函数,常用于复用逻辑(如权限验证)。
案例:封装登录状态验证的 HOC。

function withAuth(WrappedComponent) {  
  return function AuthComponent(props) {  
    const isAuthenticated = checkAuth(); // 自定义验证逻辑  
    return isAuthenticated ? <WrappedComponent {...props} /> : <Login />;  
  };  
}  

5.2 React 事件系统

React 的事件处理采用 合成事件(SyntheticEvent),与原生事件不同:

  • 区别:合成事件是跨浏览器封装,且需手动阻止默认行为(如 e.preventDefault())。
  • 面试问题

    Q:为什么不能在 useEffect 中直接使用 e 变量?
    A:因为 useEffect 的依赖项未包含 e,可能导致闭包引用过期的旧值。


六、常见陷阱与解决方案

6.1 错误处理:componentDidCatchErrorBoundary

通过 错误边界组件 捕获子组件的异常,避免整个应用崩溃。

class ErrorBoundary extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = { hasError: false };  
  }  
  static getDerivedStateFromError(error) {  
    return { hasError: true }; // 更新状态标记错误  
  }  
  render() {  
    if (this.state.hasError) {  
      return <h1>Something went wrong.</h1>;  
    }  
    return this.props.children;  
  }  
}  

6.2 防止内存泄漏:清理副作用

useEffectcomponentWillUnmount 中清理定时器、订阅等资源。

useEffect(() => {  
  const interval = setInterval(() => {}, 1000);  
  return () => clearInterval(interval); // 清理函数  
}, []);  

结论

本文围绕 “React 面试题” 分析了从基础到进阶的核心知识点,涵盖组件通信、状态管理、性能优化和常见陷阱。通过代码示例和比喻,帮助读者在理解原理的同时,掌握实际开发中的最佳实践。面试中,除了技术细节,清晰的逻辑表达和解决问题的思路同样重要。建议读者结合项目实践,深入理解 React 的设计理念,并持续关注新特性(如 React 18 的并发模式),以应对面试中的挑战。

(字数统计:约 1800 字)

最新发布