2025 年开发者必知的 17 个 React 面试问题
感谢阅读
最初发表于Medium
React是2025年前端开发人员最需要的技能之一。如果你正在准备2025 年的React开发人员面试,那么掌握最新的最佳实践、模式和概念至关重要。
本文列出了17 个 React 面试问题,涵盖了从核心React原则到高级性能优化的所有内容,可帮助您在下一次React开发人员面试中脱颖而出。
让我们开始吧!
1. 什么是 React Virtual DOM?它与真实 DOM 和 Shadow DOM 有何不同?
虚拟 DOM是一种概念,其中真实 DOM的虚拟表示保存在内存中,并且仅在必要时通过ReactDOM等库与实际DOM同步。
虚拟DOM是一个代表内存中真实 DOM 的对象。由于DOM更新是任何 Web 应用不可或缺的一部分,但却是前端开发中最昂贵的操作,因此虚拟 DOM用于检查应用中需要更新的部分,并仅更新这些部分,从而显著提升性能。
虚拟DOM与真实 DOM和影子 DOM是完全不同的概念。真实 DOM是HTML 文档以树状结构的实际表示,浏览器使用它来跟踪网页的内容;而影子 DOM是一种编程实践,允许开发人员为 Web 应用程序创建独立的可重用组件。
如果你想深入了解虚拟 DOM、真实 DOM和影子 DOM之间的区别,请查看这篇文章
2. React 中有哪两种类型的组件?我们应该在哪里使用它们?
React中有两种类型的组件:
- 类组件
- 功能组件
以前,类组件是创建具有React中任何功能的组件的唯一方法,而功能组件仅用作展示组件,通常被称为“哑”组件。
但是,随着React 16.8的发布和React Hooks的引入,函数式组件现在可以拥有状态和生命周期方法,使它们成为在React中创建组件的首选方式。
函数式组件比类组件速度更快,开销和样板代码也更少,因此建议尽可能使用函数式组件。然而,某些生命周期方法仍然只能在类组件中使用,因此在某些特殊情况下,例如创建自定义错误边界(例如:在类组件中使用生命周期方法),你可能需要使用类组件。componentDidCatch
3. 为什么 React 中需要键?在 React 中,我们可以不使用列表而直接使用键吗?
Keys
在React中,用于标识唯一的虚拟 DOM 元素及其驱动UI 的对应数据。使用keys
可帮助React通过回收现有DOM 元素来优化渲染。
Keys
帮助React识别哪些项目已更改、添加或删除,使其能够重用已经存在的DOM 元素,从而提高性能。
例如:
const Todos = ({ todos }) => {
return (
<div>
{todos.map((todo) => (
<li>{todo.text}</li>
))}
</div>
);
};
这将导致每次待办事项更改时都会创建新的DOM 元素key
,但添加prop(即<li key={todo.id}>{todo.text}</li>
:)将导致“拖动”标签内的DOM元素ul
并仅更新必要li
的
Keys
可以与React中的任何元素一起使用,不一定需要与列表一起使用,但最常用于列表以优化渲染。一些非标准(且不推荐)的用例keys
包括使用它们来强制重新渲染组件,如下例所示:
const TimeNow = () => {
const [key, setKey] = useState(0);
useEffect(() => {
const interval = setInterval(() => setKey((prevKey) => prevKey + 1), 1000);
return () => clearInterval(interval);
}, []);
return <div key={key}>{new Date()}</div>;
};
如上所述,绝对应该避免使用这样的代码,最好使用状态来存储时间,而不是使用键来强制重新渲染。使用keys
强制重新渲染是一种反模式,除非你确切知道自己在做什么,否则可能会导致严重的性能问题。
4. React 中受控输入和非受控输入的区别
受控组件依赖React 状态来管理表单数据,而非受控组件使用DOM本身来处理表单数据。
在大多数情况下,受控组件是首选,因为它们为表单数据提供了单一真实来源,从而更易于管理、验证和提交表单数据。
const ControlledInputForm = () => {
const [value, setValue] = useState("");
const handleChange = (e) => setValue(e.target.value);
const handleSubmit = (e) => {
e.preventDefault();
console.log(value);
};
return (
<form onSubmit={handleSubmit}>
<input type="text" value={value} onChange={handleChange} />
<button type="submit">Submit</button>
</form>
);
};
const UncontrolledInputForm = () => {
const inputRef = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
console.log(inputRef.current.value);
};
return (
<form onSubmit={handleSubmit}>
<input type="text" ref={inputRef} />
<button type="submit">Submit</button>
</form>
);
};
5.为什么我们需要转译 JSX 代码?
除非你伤到了头,否则你不会像这样使用React :
import { createElement } from "react";
const Greeting = ({ name }) => {
return createElement("h1", { className: "greeting" }, "Hello");
};
然而,这就是浏览器读取的内容——它根本无法理解通常用于编写React 组件的JSX 语法。
因此,我们需要使用Babel之类的工具将JSX 转换为JavaScript,以便浏览器可以执行它。因此,当你编写以下代码时:
const Greeting = ({ name }) => <h1 className="greeting">Hello</h1>;
它被转换为前面的代码片段,以便浏览器可以解释它并呈现组件。
6.JSX 如何防止注入攻击?

由于JSX将内容渲染为文本,因此用户输入的任何元素都不会被视为HTML,而只是纯文本。例如,以下script
标签将被渲染为文本,而不会执行:
const MyComponent = () => {
const content = "<script>alert('XSS')</script>";
return <div>{content}</div>;
};
注意:您可以使用来覆盖此行为,dangerouslySetInnerHTML
但不建议这样做,除非您绝对确定输入的来源(并且强烈建议在注入之前清理内容)。
const MyComponent = () => {
const content = "<script>alert('XSS')</script>";
return <div dangerouslySetInnerHTML={{ __html: content }} />;
};
7. 如何为 React 组件添加样式?
CSS 文件
使用CSS文件是设置React 组件样式的最常用方法之一。它允许使用所有CSS特性,并且在Create React App中已默认设置。
/* Button.css */
.button {
background-color: blue;
color: white;
}
// Button.tsx
import "./Button.css";
const Button = () => {
return <button className="button">Click me</button>;
};
内联 CSS
使用内联CSS为React 元素添加样式,可以将样式完全限定在元素范围内。但是,某些样式功能不适用于内联样式。例如,像 这样的伪类的样式。:hover
const Button = () => {
return (
<button style={{ backgroundColor: "blue", color: "white" }}>
Click me
</button>
);
};
CSS-in-JS 模块(Styled Components、Emotion 和 Styled-jsx)
CSS-in-JS模块是设计React 应用程序样式的热门选择,因为它们与React 组件紧密集成。例如,它们允许样式在运行时根据React props进行更改。此外,默认情况下,大多数此类系统会将所有样式限定在相应的组件上。
import styled from "styled-components";
const Button = styled.button`
background-color: blue;
color: white;
`;
const App = () => {
return <Button>Click me</Button>;
};
CSS 模块
我个人最喜欢的样式方法,CSS 模块允许将样式限定在单个组件内。这是一种避免类名冲突(类名冲突指的是两个类名相同——这在大型项目中很常见)的好方法,可以保持样式的井然有序,并能将共享样式添加到多个组件。
/* Button.module.css */
.button {
background-color: blue;
color: white;
}
// Button.js
import styles from "./Button.module.css";
const Button = () => {
return <button className={styles.button}>Click me</button>;
};
8. React 中的合成事件是什么?
合成事件将不同浏览器原生事件的响应组合成一个 API,确保事件在不同浏览器中保持一致。无论应用程序在哪个浏览器中运行,它都是一致的。
const Component = () => {
const handleClick = (e) => {
e.preventDefault(); // synthetic event
console.log("link clicked");
};
return <a onClick={(e) => handleClick}>Click me</a>;
};
9.React 中的严格模式是什么?
<StrictMode />
是React内置的一个组件,用于提供组件中潜在问题的额外可见性。如果应用程序在开发模式下运行,则任何出现的问题都会记录到开发控制台中;但如果应用程序在生产模式下运行,则不会显示这些警告。
开发人员使用它<StrictMode />
来查找诸如弃用的生命周期方法和遗留模式等问题,以确保所有React 组件都遵循当前的最佳实践。
<StrictMode />
可以应用于应用程序组件层次结构的任何级别,从而允许在代码库中逐步采用它。
文档<StrictMode />
添加如下
严格模式支持以下仅限开发的行为:
- 您的组件将重新渲染一次,以查找由不纯渲染引起的错误。
- 您的组件将额外重新运行效果以查找因缺少效果清理而导致的错误。
- 您的组件将额外重新运行 refs 回调以查找因缺少 ref 清理而导致的错误。
- 您的组件将被检查是否使用了弃用的 API。
10. 如何优雅地处理 React 中的错误?
默认情况下,如果React 应用在渲染过程中抛出错误,React会将其 UI 从屏幕上移除。为了防止这种情况,我们可以将部分 UI 包裹到错误边界中,这样我们就可以捕获错误并显示回退 UI,而不会导致整个应用崩溃。
您可以构建自定义错误边界:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI, or even accept it as a prop
return <FallbackComponent />;
}
return this.props.children;
}
}
但大多数情况下,您可以使用react-error-boundary
提供必要组件来处理React 应用程序中的错误。
import { ErrorBoundary } from "react-error-boundary";
const App = () => (
<ErrorBoundary FallbackComponent={FallbackComponent}>
<MyComponent />
</ErrorBoundary>
);
11.React Hooks 的规则是什么?
React Hooks有 3 条主要规则:
- 仅从 React 函数中调用 Hooks:Hooks只能在React 函数组件中或从其他Hooks中调用。在常规JS / TS函数中调用Hooks将被视为常规函数调用,并且无法按预期工作。
- 仅在顶层调用 hooks:Hooks只能在React 函数组件或自定义 hooks的顶层调用。这是为了确保每次组件渲染时hooks都以相同的顺序调用。在循环、条件或嵌套函数中使用hooks将导致错误。
- Hooks 必须以 'use' 开头:所有hooks 的名称(包括自定义 hooks )都必须以"use"开头。这是为了确保React能够识别hooks并强制执行hooks的规则。例如,
useState
,useEffect
,useContext
等等。
12. 如何处理 React 函数组件中的常见生命周期方法?
React中常见的生命周期方法有:
componentDidMount
:组件挂载到DOM后调用。通常用于获取数据或执行诸如添加事件监听器之类的副作用。componentDidUpdate
:在组件中某个特定值更新后调用。通常用于根据更新后的值执行一些副作用。componentWillUnmount
:组件从DOM中卸载之前调用的清理方法。通常用于移除事件监听器或取消网络请求。
在函数式组件中,这些生命周期方法可以通过使用useEffect
钩子来处理。useEffect
钩子的第一个参数是一个函数,第二个参数是一个依赖项数组。
const Component = () => {
useEffect(() => {
// componentDidMount
console.log("Component mounted");
return () => {
// componentWillUnmount
console.log("Component unmounted");
};
}, []); // empty dependency array implies this effect runs only once when the component mounts
useEffect(
() => {
// componentDidUpdate
console.log("Component updated");
},
[
/* dependencies - changes to these values should trigger the function to re-run */
/* NOTE: This function will run during mount too */
]
);
return <React.Fragment />;
};
13. React 中的 refs 是什么?
Refs
是允许您在渲染之间保留数据的变量,就像变量一样state
,但与state
变量不同的是,更新refs
不会导致组件重新渲染。
Refs
通常用于(但不限于)存储对DOM 元素的引用。
const Component = () => {
const inputRef = useRef(null);
const handleClick = () => inputRef.current.focus();
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={handleClick}>Focus Input</button>
</div>
);
};
14. React 中的 prop 钻孔是什么?如何避免它?
在开发React 应用程序时,经常需要将数据从层次结构中较高的组件传递到深度嵌套的组件。Prop钻取是指将props从源组件通过所有中间组件传递到深度嵌套组件的过程。
使用prop 钻取的缺点是,原本不应该知道数据的组件可以访问数据,而且代码变得更难维护。
可以使用Context API或某种形式的状态管理库来避免Prop 钻取。
15. 描述 React 中的一些优化技术
使用记忆化
useMemo
是一个用于缓存CPU 开销大函数的React hook。由于组件重新渲染而反复调用CPU 开销大函数可能会导致严重的性能问题和用户体验下降。
该useMemo
钩子可用于缓存此类函数的结果。通过使用useMemo
,仅在需要时调用CPU 开销较大的函数。
延迟加载
延迟加载是一种用于减少React 应用初始加载时间的技术。通过在用户浏览应用时加载组件,它有助于将 Web 应用性能风险降至最低。
节流和去抖
虽然这不是React 独有的优化技术,但它经常在React 应用程序中用于提升性能。节流和去抖是用于限制函数响应事件调用次数的技术——它们通常与为用户提供实时反馈的输入一起使用(例如:在带有自动建议的搜索字段中输入内容——可以对获取建议的API 调用进行节流或去抖动,以避免进行不必要的API 调用)。
16.什么是门户?

建议使用Portal将子组件渲染到父组件DOM 层次结构之外的DOM 节点中。建议为portal创建一个新的DOM 节点。
const Portal = ({ children }) => {
// NOTE: it is assumed that the portal root is already present in the HTML file
// <div id="portal-root" />
const portalRoot = document.getElementById("portal-root");
return ReactDOM.createPortal(children, portalRoot);
};
17.什么是 React Fiber?
React Fiber是ReactJS的一个概念,用于使系统渲染更快、更流畅。这是一次内部引擎改进,旨在使React更快、更“智能”。Fiber协调器已成为React 16及更高版本的默认协调器,它完全重写了React 的协调算法,以解决React中一些长期存在的问题。
由于Fiber是异步的,因此React可以:
- 随着新更新的到来,暂停、恢复和重新启动组件的渲染工作
- 重复使用以前完成的工作,甚至在不需要时中止它
- 将工作分成多个部分,并根据重要性确定任务的优先级
这一变化使React摆脱了之前同步Stack Reconciler的限制,即任务无法被中断。此外,这一变化还允许React对渲染组件进行微调,确保最重要的更新尽快完成。
您是否正在摸不着头脑,不明白“和解”到底是什么?
别担心,我们帮你搞定!在React中,协调 (reconciliation)是负责高效更新UI以响应组件状态或 props 变化的核心机制。它决定了将实际DOM转换为虚拟 DOM所表示的期望状态所需的最小操作集。
就这些啦,朋友们!🎉
如果你想要一份React Native面试题列表,请继续关注下一篇文章!
感谢阅读
需要一位顶级软件开发自由职业者来解决你的开发难题吗?在Upwork上联系我
想联系我吗?请在LinkedIn上联系我
关注我的博客,每两周在Medium上获取最新资讯
常问问题
这些是我收到的一些常见问题。希望这个常见问题解答部分能解决您的问题。
-
我是初学者,该如何学习前端 Web 开发?
可以参考以下文章: -
你能指导我吗?
抱歉,我工作很忙,没时间指导任何人。