react精简面试题
一、React 基础
1. React 的核心特性是什么?
答案:
-
组件化开发:将 UI 拆分为独立可复用的组件。
-
虚拟 DOM(Virtual DOM):通过内存中的轻量级 DOM 结构优化真实 DOM 操作。
-
单向数据流:数据通过 props 从父组件传递到子组件,状态变化可预测。
-
JSX:允许在 JavaScript 中编写类似 HTML 的语法,增强代码可读性。
2. 类组件和函数组件的区别?
答案:
-
类组件:
-
使用
class
定义,继承React.Component
。 -
有生命周期方法(如
componentDidMount
)。 -
通过
this.state
和this.setState
管理状态。
-
-
函数组件:
-
使用函数定义,更简洁。
-
通过 Hooks(如
useState
,useEffect
)管理状态和副作用。 -
无
this
绑定问题,性能更优(配合 React 优化策略)。
-
3. 什么是 JSX?它的作用是什么?
答案:
-
JSX 是 JavaScript 的语法扩展,允许在 JavaScript 中编写类似 HTML 的结构。
-
作用:
-
更直观地描述 UI 结构。
-
最终会被 Babel 编译为
React.createElement()
调用,生成 React 元素。
-
-
示例:
jsx
复制
const element = <h1 className="title">Hello, React!</h1>;
二、React 核心机制
4. React 如何实现高效更新?虚拟 DOM 的原理是什么?
答案:
-
虚拟 DOM 是一个轻量级的 JavaScript 对象,表示真实 DOM 的副本。
-
更新流程:
-
当状态变化时,React 生成新的虚拟 DOM。
-
通过 Diff 算法 对比新旧虚拟 DOM 的差异。
-
仅将差异部分更新到真实 DOM(批量更新)。
-
-
优势:减少直接操作真实 DOM 的次数,提升性能。
5. React 中的 key 属性有什么作用?
答案:
-
作用:帮助 React 识别列表元素的唯一性,优化 Diff 算法效率。
-
正确用法:
-
使用唯一且稳定的值(如数据库 ID)。
-
避免使用数组索引(可能导致渲染错误或性能问题)。
-
6. 什么是受控组件和非受控组件?
答案:
-
受控组件:
-
表单数据由 React 组件管理(通过
state
和onChange
)。 -
示例:
<input value={value} onChange={handleChange} />
-
-
非受控组件:
-
表单数据由 DOM 自身管理(通过
ref
获取值)。 -
示例:
<input ref={inputRef} defaultValue="初始值" />
-
三、Hooks 深入
7. useEffect 的依赖数组如何工作?
答案:
-
无依赖数组:每次渲染后执行。
js
复制
useEffect(() => { ... });
-
空数组:仅在组件挂载和卸载时执行。
js
复制
useEffect(() => { ... }, []);
-
有依赖项:当依赖项变化时执行。
js
复制
useEffect(() => { ... }, [count]);
8. 如何实现自定义 Hook?
答案:
-
自定义 Hook 是一个以
use
开头的函数,内部可调用其他 Hooks。 -
示例:实现一个记录窗口宽度的 Hook:
js
复制
function useWindowWidth() { const [width, setWidth] = useState(window.innerWidth); useEffect(() => { const handleResize = () => setWidth(window.innerWidth); window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); return width; }
9. useMemo 和 useCallback 的区别?
答案:
-
useMemo:缓存计算结果,避免重复计算。
js
复制
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
-
useCallback:缓存函数引用,避免子组件不必要的重渲染。
js
复制
const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b]);
四、高级主题
10. React Context 如何解决组件间通信问题?
答案:
-
Context 的作用:跨层级组件共享数据,避免逐层传递 props。
-
实现步骤:
-
创建 Context:
const MyContext = React.createContext(defaultValue);
-
提供数据:
<MyContext.Provider value={value}>
-
消费数据:
useContext(MyContext)
或<MyContext.Consumer>
-
11. React 性能优化的常见手段有哪些?
答案:
-
组件优化:
-
使用
React.memo
缓存函数组件。 -
类组件实现
shouldComponentUpdate
或继承PureComponent
。
-
-
状态管理:
-
避免在渲染函数中频繁创建新对象/函数。
-
使用
useMemo
和useCallback
缓存值和函数。
-
-
代码分割:
-
使用
React.lazy
和Suspense
实现按需加载组件。
-
12. React Fiber 是什么?解决了什么问题?
答案:
-
Fiber 是 React 16 引入的新的协调算法核心。
-
解决的问题:
-
将渲染任务拆分为多个小任务(可中断和恢复)。
-
实现异步渲染(Concurrent Mode),避免长时间阻塞主线程。
-
支持优先级调度(如动画优先更新)。
-
五、综合实战
13. 如何实现一个高阶组件(HOC)?
答案:
-
高阶组件 是一个函数,接收组件并返回增强后的新组件。
-
示例:实现一个日志记录的 HOC:
js
复制
function withLogger(WrappedComponent) { return function(props) { useEffect(() => { console.log('Component mounted'); return () => console.log('Component unmounted'); }, []); return <WrappedComponent {...props} />; }; }
14. React 中如何处理错误边界(Error Boundaries)?
答案:
-
错误边界 是类组件,通过
static getDerivedStateFromError()
和componentDidCatch()
捕获子组件的错误。 -
示例:
js
复制
class ErrorBoundary extends React.Component { state = { hasError: false }; static getDerivedStateFromError(error) { return { hasError: true }; } componentDidCatch(error, info) { logErrorToService(error, info); } render() { return this.state.hasError ? <FallbackUI /> : this.props.children; } }
六、附加问题(React 18+)
15. React 18 引入了哪些新特性?
答案:
-
并发模式(Concurrent Mode):支持任务优先级和中断渲染。
-
自动批处理(Automatic Batching):优化状态更新合并逻辑。
-
新的 Root API:使用
createRoot
替代ReactDOM.render
。 -
Suspense 增强:支持数据获取和服务器端渲染(SSR)。