《前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux… 。

文章目录
- 一、本文面试题目录
- 61. 什么是 React.lazy 和 Suspense?它们的作用是什么?
- 62. 什么是React的Context API?如何避免性能问题?
- 63. 如何在React中实现表单验证?
- 64. 如何在React中实现文件上传?
- 65. 如何优化 React 应用的性能?请列举至少 3 种方法。
- 66. 什么是 Context API?如何避免 Context 导致的组件重新渲染?
- 67. 什么是 React 的合成事件(SyntheticEvent)?它的工作原理是什么?
- 68. 什么是 React Fiber?它解决了什么问题?
- 69. 如何在React中实现单元测试?
- 70. 如何在 React 中实现路由?
一、本文面试题目录
61. 什么是 React.lazy 和 Suspense?它们的作用是什么?
答案:
React.lazy 和 Suspense 是 React 16.6 引入的特性,用于实现组件的懒加载(Code Splitting)。
- React.lazy: 允许你动态导入组件,使组件在需要时才加载。
- Suspense: 用于包裹懒加载的组件,在组件加载完成前显示加载状态(如加载动画)。
原理:
懒加载通过 Webpack 等打包工具将代码分割成多个小块,减少初始加载时间。Suspense 则处理加载过程中的状态管理。
示例代码:
// 懒加载组件
const LazyComponent = React.lazy(() => import('./LazyComponent'));
function App() {
return (
<div>
<React.Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</React.Suspense>
</div>
);
}
62. 什么是React的Context API?如何避免性能问题?
Context API 用于跨层级传递数据,避免props drilling。
性能优化:
-
拆分Context:
const UserContext = React.createContext(); const ThemeContext = React.createContext(); <UserContext.Provider value={user}> <ThemeContext.Provider value={theme}> <App /> </ThemeContext.Provider> </UserContext.Provider> -
使用useMemo缓存值:
const contextValue = useMemo(() => ({ user, setUser }), [user]); <UserContext.Provider value={contextValue}> {children} </UserContext.Provider> -
避免深层嵌套:
// 不好的写法 <Context.Provider value={value}> <DeeplyNestedComponent /> </Context.Provider> // 优化:将Provider靠近消费组件 <ParentComponent> <Context.Provider value={value}> <ChildComponent /> </Context.Provider> </ParentComponent>
63. 如何在React中实现表单验证?
表单验证方案:
-
受控组件 + 状态管理:
const [formData, setFormData] = useState({ name: '', email: '' }); const [errors, setErrors] = useState({}); const validate = () => { let tempErrors = {}; if (!formData.name) tempErrors.name = 'Name is required'; if (!formData.email) tempErrors.email = 'Email is required'; return Object.keys(tempErrors).length === 0 ? null : tempErrors; }; const handleSubmit = (e) => { e.preventDefault(); const validationErrors = validate(); if (validationErrors) { setErrors(validationErrors); } else { // 提交表单 } }; return ( <form onSubmit={handleSubmit}> <input type="text" value={formData.name} onChange={(e) => setFormData({ ...formData, name: e.target.value })} /> {errors.name && <span>{errors.name}</span>} </form> ); -
使用第三方库(Formik + Yup):
import { Formik, Form, Field, ErrorMessage } from 'formik'; import * as Yup from 'yup'; const validationSchema = Yup.object({ name: Yup.string().required('Required'), email: Yup.string().email('Invalid email').required('Required'), }); return ( <Formik initialValues={{ name: '', email: '' }} validationSchema={validationSchema} onSubmit={handleSubmit} > <Form> <Field name="name" /> <ErrorMessage name="name" component="span" /> <button type="submit">Submit</button> </Form> </Formik> );
64. 如何在React中实现文件上传?
文件上传实现:
-
基本表单上传:
const [selectedFile, setSelectedFile] = useState(null); const handleFileChange = (e) => { setSelectedFile(e.target.files[0]); }; const handleUpload = () => { const formData = new FormData(); formData.append('file', selectedFile); fetch('/api/upload', { method: 'POST', body: formData, }) .then((response) => response.json()) .then((data) => console.log(data)); }; return ( <div> <input type="file" onChange={handleFileChange} /> <button onClick={handleUpload}>Upload</button> </div> ); -
多文件上传:
<input type="file" multiple onChange={handleFileChange} /> const handleFileChange = (e) => { const files = Array.from(e.target.files); files.forEach((file) => { // 处理每个文件 }); }; -
上传进度显示:
const [progress, setProgress] = useState(0); const uploadFile = (file) => { const xhr = new XMLHttpRequest(); xhr.upload.onprogress = (e) => { if (e.lengthComputable) { setProgress((e.loaded / e.total) * 100); } }; xhr.open('POST', '/api/upload'); xhr.send(file); };
65. 如何优化 React 应用的性能?请列举至少 3 种方法。
答案:
-
使用 shouldComponentUpdate 或 React.memo:
shouldComponentUpdate(类组件):通过比较 props/state 决定是否重新渲染。React.memo(函数组件):浅比较 props,避免不必要的渲染。
-
虚拟列表(Virtualized List):
只渲染可视区域的列表项,适用于大数据量列表(如 react-window 或 react-virtualized)。 -
懒加载(Code Splitting):
使用 React.lazy 和 Suspense 分割代码,减少初始加载时间。 -
使用 useMemo 和 useCallback:
useMemo:缓存计算结果,避免重复计算。useCallback:缓存函数引用,避免子组件因 props 变化而重新渲染。
示例代码:
// 使用 React.memo
const MemoizedComponent = React.memo(({ data }) => {
return <div>{data}</div>;
});
// 使用 useMemo 缓存计算结果
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
66. 什么是 Context API?如何避免 Context 导致的组件重新渲染?
答案:
Context API 允许你在组件树中共享数据,避免通过 props 层层传递(“prop drilling”)。
避免重新渲染的方法:
- 拆分 Context: 将高频变化的数据和低频变化的数据分离到不同的 Context 中。
- 使用 useMemo 包裹 Provider: 避免 Provider 的 value 引用变化。
- 将 Consumer 组件提取到单独文件: 减少父组件更新对 Consumer 的影响。
示例代码:
// 创建 Context
const UserContext = React.createContext();
// 提供者组件
function UserProvider({ children }) {
const user = useContextValue(); // 假设这是一个自定义 Hook
const memoizedValue = useMemo(() => ({ user }), [user]);
return (
<UserContext.Provider value={memoizedValue}>
{children}
</UserContext.Provider>
);
}
67. 什么是 React 的合成事件(SyntheticEvent)?它的工作原理是什么?
答案:
合成事件是 React 封装的跨浏览器兼容的事件系统,统一了不同浏览器的事件接口(如 onClick、onChange)。
工作原理:
- 事件委托(Event Delegation): React 将所有事件绑定到文档根节点(document)。
- 事件对象包装: 将原生事件包装成合成事件对象,提供一致的 API(如 e.preventDefault())。
- 事件池(Event Pooling): 复用事件对象以提高性能(React 17 已移除)。
示例代码:
function Button({ onClick }) {
return (
<button onClick={(e) => {
e.preventDefault(); // 合成事件方法
onClick();
}}>
Click me
</button>
);
}
68. 什么是 React Fiber?它解决了什么问题?
答案:
React Fiber 是 React 16.x 版本引入的协调算法(Reconciliation)的重新实现。
主要改进:
- 任务分片(Task Slicing): 将渲染任务分成多个小任务,允许中断和恢复。
- 优先级调度: 高优先级任务(如动画)可插队执行。
- 更好的用户体验: 避免长时间阻塞主线程,减少页面卡顿。
解决的问题:
在大型应用中,旧的协调算法可能导致长时间的渲染阻塞,影响用户体验。Fiber 通过增量渲染(Incremental Rendering)解决了这个问题。
69. 如何在React中实现单元测试?
单元测试实现:
-
使用Jest + React Testing Library:
// 组件 function Button({ onClick, text }) { return <button onClick={onClick}>{text}</button>; } // 测试 import { render, fireEvent } from '@testing-library/react'; test('Button click triggers callback', () => { const mockClick = jest.fn(); const { getByText } = render(<Button onClick={mockClick} text="Click me" />); fireEvent.click(getByText('Click me')); expect(mockClick).toHaveBeenCalledTimes(1); }); -
测试异步操作:
test('Fetches data on button click', async () => { const mockFetch = jest.fn(() => Promise.resolve({ json: () => Promise.resolve({ name: 'Test' }) }) ); global.fetch = mockFetch; const { getByText } = render(<FetchButton />); fireEvent.click(getByText('Fetch')); await waitFor(() => expect(getByText('Test')).toBeInTheDocument()); }); -
测试状态更新:
test('Counter increments on click', () => { const { getByText } = render(<Counter />); const button = getByText('0'); fireEvent.click(button); expect(getByText('1')).toBeInTheDocument(); });
70. 如何在 React 中实现路由?
答案:
React 本身不提供路由功能,通常使用第三方库如 react-router-dom。
主要概念:
BrowserRouter:使用 HTML5 History API 实现路由。Routes和Route:定义路由匹配规则。Link:导航链接。useNavigate:编程式导航。
示例代码:
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
function App() {
return (
<Router>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Router>
);
}
1832

被折叠的 条评论
为什么被折叠?



