Appearance
100道高频React面试题 - 完整题库精选
基础概念 (1-20题)
1. React是什么?它的主要特点是什么?
答案:
React是Facebook开发的JavaScript库,用于构建用户界面。
主要特点:
1. 声明式: 描述UI应该是什么样
2. 组件化: 可复用的组件
3. Virtual DOM: 提升性能
4. 单向数据流: 数据自上而下流动
5. JSX语法: JavaScript + XML
6. Learn Once, Write Anywhere: 可用于Web/Native/VR2. JSX是什么?它是如何工作的?
答案:
JSX是JavaScript XML的语法扩展。
工作原理:
1. Babel编译JSX为React.createElement调用
2. createElement创建React Element (Virtual DOM)
3. React渲染Virtual DOM到真实DOM
示例:
<div>Hello</div>
↓ 编译为
React.createElement('div', null, 'Hello')3. 组件和元素的区别?
答案:
元素(Element):
- React.createElement的返回值
- 普通JavaScript对象
- 描述DOM节点或组件实例
- 不可变的
组件(Component):
- 函数或类
- 接收props返回元素
- 可以有状态和生命周期
- 可复用的
关系: 组件返回元素,元素描述UI4. 函数组件和类组件的区别?
答案:
函数组件:
- 简单的JavaScript函数
- 使用Hooks管理状态
- 没有this
- 性能更好
- 推荐使用
类组件:
- ES6类
- 使用this.state和生命周期方法
- 有this绑定问题
- 较复杂
- 逐渐被函数组件替代5. Props和State的区别?
答案:
Props:
- 父组件传递给子组件
- 只读,不可修改
- 用于组件间通信
State:
- 组件内部状态
- 可以通过setState/useState修改
- 触发重新渲染
- 私有的6. 什么是受控组件和非受控组件?
答案:
受控组件:
- value由React state控制
- onChange更新state
- 单一数据源
非受控组件:
- value由DOM自己管理
- 使用ref访问值
- 类似传统HTML表单7. React中的key有什么作用?
答案:
作用:
1. 帮助React识别哪些项变化/添加/删除
2. 优化列表渲染性能
3. 保持组件状态稳定
要求:
- 唯一且稳定
- 不建议使用索引(除非静态列表)8. 为什么不能用索引作为key?
答案:
问题:
1. 列表重排序时索引变化
2. 导致错误的组件复用
3. 可能丢失组件状态
4. 性能优化失效
示例:
[A, B, C] -> [C, A, B]
使用索引: key 0,1,2 -> 0,1,2 (React认为内容变了)
使用ID: key a,b,c -> c,a,b (React知道是移动)9. 什么是Virtual DOM?
答案:
Virtual DOM是DOM的JavaScript对象表示。
优势:
1. 减少直接DOM操作
2. 批量更新
3. 跨平台能力
4. Diff算法优化
工作流程:
1. 状态变化
2. 创建新Virtual DOM
3. Diff算法比较
4. 最小化更新真实DOM10. React生命周期有哪些?
答案:
挂载:
- constructor
- getDerivedStateFromProps
- render
- componentDidMount
更新:
- getDerivedStateFromProps
- shouldComponentUpdate
- render
- getSnapshotBeforeUpdate
- componentDidUpdate
卸载:
- componentWillUnmount
错误:
- getDerivedStateFromError
- componentDidCatchHooks (21-40题)
21. useState的工作原理?
答案:
1. mount时创建Hook节点,初始化状态
2. 状态存储在Fiber.memoizedState链表
3. setState创建更新对象,加入队列
4. update时处理更新队列,计算新状态
5. 触发重新渲染
特点:
- 异步批量更新
- 支持函数式更新
- dispatch引用稳定22. useEffect的执行时机?
答案:
执行时机:
- mount: 组件渲染完成后异步执行
- update: 依赖变化后异步执行
- unmount: 执行cleanup
与useLayoutEffect区别:
- useEffect: 异步,不阻塞渲染
- useLayoutEffect: 同步,阻塞渲染23. useEffect的依赖数组如何工作?
答案:
- 无deps: 每次渲染都执行
- 空deps []: 只在mount时执行
- 有deps: deps变化时执行
比较方式:
- 使用Object.is浅比较
- 对象/数组按引用比较24. useMemo和useCallback的区别?
答案:
useMemo:
- 缓存计算结果
- 返回值
useCallback:
- 缓存函数引用
- 返回函数
关系:
useCallback(fn, deps) = useMemo(() => fn, deps)25. useRef的作用?
答案:
作用:
1. 访问DOM节点
2. 保存可变值(不触发渲染)
3. 保持跨渲染的引用
特点:
- .current可变
- 改变不触发渲染
- 引用稳定26. useContext的使用场景?
答案:
使用场景:
1. 跨层级传递数据
2. 主题切换
3. 用户信息
4. 多语言
5. 全局配置
优势:
- 避免props drilling
- 组件解耦
注意:
- 会导致所有消费者重渲染
- 需要优化拆分Context27. useReducer vs useState?
答案:
useReducer适用:
- 复杂状态逻辑
- 多个子值
- 状态依赖前一状态
- 需要dispatch稳定引用
useState适用:
- 简单状态
- 独立更新
代码示例:
const [state, dispatch] = useReducer(reducer, initialState);28. 自定义Hook的规则?
答案:
命名规则:
- 必须以use开头
调用规则:
- 只能在顶层调用
- 只能在函数组件或其他Hook中调用
- 不能在条件/循环中调用
优势:
- 复用状态逻辑
- 分离关注点
- 提取业务逻辑29. useImperativeHandle的作用?
答案:
作用:
- 自定义暴露给父组件的ref值
- 通常与forwardRef一起使用
示例:
useImperativeHandle(ref, () => ({
focus: () => inputRef.current.focus(),
reset: () => inputRef.current.value = ''
}));
场景:
- 封装复杂组件
- 控制暴露的API30. useLayoutEffect vs useEffect?
答案:
useLayoutEffect:
- 同步执行
- DOM更新后立即执行
- 阻塞渲染
- 用于DOM测量
useEffect:
- 异步执行
- 渲染完成后执行
- 不阻塞渲染
- 用于副作用
选择:
- 需要读取布局 -> useLayoutEffect
- 其他情况 -> useEffect31. React Hooks的调用顺序为什么重要?
答案:
原因:
- Hooks存储在链表中
- 通过调用顺序关联状态
- 顺序变化导致状态错位
示例(错误):
if (condition) {
useState(0); // 条件调用会打乱顺序
}
正确:
const [state, setState] = useState(0);
if (condition) {
setState(1); // 在Hook外使用
}32. useTransition是什么?
答案:
定义: React 18并发特性,标记非紧急更新
使用:
const [isPending, startTransition] = useTransition();
startTransition(() => {
setQuery(input); // 低优先级更新
});
场景:
- 搜索输入
- 标签切换
- 路由跳转33. useDeferredValue的作用?
答案:
作用: 延迟更新值,优先响应用户输入
示例:
const deferredQuery = useDeferredValue(query);
与useTransition对比:
- useTransition: 控制更新
- useDeferredValue: 延迟值
场景:
- 搜索结果
- 大列表渲染34. useId的使用场景?
答案:
作用: 生成唯一ID,SSR安全
使用:
const id = useId();
<label htmlFor={id}>Name</label>
<input id={id} />
场景:
- 表单关联
- 无障碍属性
- 避免ID冲突35. useSyncExternalStore是什么?
答案:
作用: 订阅外部store,支持并发特性
使用:
const value = useSyncExternalStore(
subscribe,
getSnapshot,
getServerSnapshot
);
场景:
- 状态管理库
- 浏览器API订阅
- WebSocket数据36. useInsertionEffect的作用?
答案:
作用: CSS-in-JS库注入样式
特点:
- 在DOM变更前执行
- 早于useLayoutEffect
- 只能在DOM插入时使用
使用:
useInsertionEffect(() => {
document.head.appendChild(style);
});
场景:
- CSS-in-JS
- 样式库37. 如何实现自定义useDebounce?
javascript
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debouncedValue;
}38. 如何实现useThrottle?
javascript
function useThrottle(value, delay) {
const [throttledValue, setThrottledValue] = useState(value);
const lastRan = useRef(Date.now());
useEffect(() => {
const timer = setTimeout(() => {
if (Date.now() - lastRan.current >= delay) {
setThrottledValue(value);
lastRan.current = Date.now();
}
}, delay - (Date.now() - lastRan.current));
return () => clearTimeout(timer);
}, [value, delay]);
return throttledValue;
}39. 如何实现usePrevious?
javascript
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}40. 如何实现useLocalStorage?
javascript
function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
});
const setStoredValue = (newValue) => {
setValue(newValue);
localStorage.setItem(key, JSON.stringify(newValue));
};
return [value, setStoredValue];
}性能优化 (41-60题)
41. 如何优化React性能?
答案:
1. 使用React.memo避免重渲染
2. useMemo缓存计算结果
3. useCallback缓存函数
4. 代码分割和懒加载
5. 虚拟滚动处理大列表
6. 使用key优化列表
7. 避免内联对象/函数
8. Context优化42. React.memo的工作原理?
答案:
作用: 对函数组件props做浅比较
原理:
1. 缓存上次渲染结果
2. 新props和旧props浅比较
3. 相等则返回缓存结果
4. 不等则重新渲染
自定义比较:
React.memo(Component, (prevProps, nextProps) => {
return prevProps.id === nextProps.id;
});43. 如何避免不必要的重渲染?
答案:
方法:
1. React.memo包裹组件
2. 使用useMemo/useCallback
3. 状态下放
4. 组件拆分
5. children prop模式
6. 避免内联对象/函数44. 什么是代码分割?
答案:
定义: 将代码拆分成小块,按需加载
实现方式:
1. React.lazy动态导入
2. 路由级分割
3. 组件级分割
示例:
const LazyComponent = React.lazy(() => import('./Component'));
<Suspense fallback={<Loading />}>
<LazyComponent />
</Suspense>
优势:
- 减少初始加载
- 提升首屏速度
- 按需加载资源45. 虚拟滚动是什么?
答案:
定义: 只渲染可见区域的列表项
原理:
1. 计算可见区域
2. 只渲染可见项+缓冲项
3. 监听滚动更新
库:
- react-window
- react-virtualized
适用场景:
- 长列表(1000+项)
- 表格
- 聊天记录46. 如何优化Context性能?
答案:
优化方法:
1. 拆分Context
2. 使用useMemo包装value
3. 使用React.memo隔离消费者
4. 状态分离(provider pattern)
示例:
const value = useMemo(
() => ({ user, theme }),
[user, theme]
);
<Context.Provider value={value}>47. 懒加载图片怎么实现?
javascript
function LazyImage({ src, alt }) {
const [inView, setInView] = useState(false);
const ref = useRef();
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setInView(true);
observer.disconnect();
}
}
);
if (ref.current) {
observer.observe(ref.current);
}
return () => observer.disconnect();
}, []);
return (
<img
ref={ref}
src={inView ? src : placeholder}
alt={alt}
/>
);
}48. 如何优化大型表单性能?
答案:
优化策略:
1. 字段级状态管理
2. 使用非受控组件
3. 使用表单库(React Hook Form)
4. 虚拟化长表单
5. 分步骤表单
6. 防抖提交49. React性能分析工具有哪些?
答案:
工具:
1. React DevTools Profiler
2. Chrome DevTools Performance
3. Lighthouse
4. why-did-you-render
5. React.Profiler API
使用:
<Profiler id="App" onRender={callback}>
<App />
</Profiler>50. 什么是Concurrent Mode?
答案:
定义: React 18并发渲染机制
特点:
- 可中断渲染
- 优先级调度
- 自动批处理
- Suspense data fetching
开启:
createRoot(container).render(<App />)
API:
- useTransition
- useDeferredValue
- startTransition51. 如何优化首屏加载?
答案:
策略:
1. 代码分割
2. 路由懒加载
3. 图片懒加载
4. 预加载关键资源
5. SSR/SSG
6. Tree Shaking
7. 压缩资源
8. CDN加速52. 什么是Tree Shaking?
答案:
定义: 移除未使用的代码
要求:
- ES6 modules
- 纯函数
- sideEffects配置
webpack配置:
{
"sideEffects": false
}
优势:
- 减小bundle大小
- 提升加载速度53. 如何处理组件间的性能隔离?
答案:
方法:
1. React.memo隔离
2. 状态下放
3. Context拆分
4. children prop
5. render props
示例:
function Slow Component({ children }) {
return (
<div>
<ExpensiveComputation />
{children}
</div>
);
}
<SlowComponent>
<FastComponent /> {/* 不会因父组件重渲染 */}
</SlowComponent>54. 批量更新是如何工作的?
答案:
React 18:
- 自动批量更新所有更新
- 包括setTimeout、Promise、原生事件
React 17:
- 只批量处理React事件
- 其他需要手动批处理
强制批处理:
import { unstable_batchedUpdates } from 'react-dom';
unstable_batchedUpdates(() => {
setState1();
setState2();
});55. 如何优化条件渲染?
答案:
优化方法:
1. 提前return
2. 使用&&短路
3. 三元运算符
4. 拆分组件
5. useMemo缓存
不推荐:
if (condition) return <ComponentA />
return <ComponentB />
推荐:
return condition ? <ComponentA /> : <ComponentB />56. 如何优化事件处理器?
答案:
优化方法:
1. useCallback缓存函数
2. 事件委托
3. 使用事件对象池
4. 避免bind
示例:
const handleClick = useCallback((id) => {
console.log(id);
}, []);
<button onClick={() => handleClick(id)}>57. 为什么不要在render中创建组件?
答案:
问题:
1. 每次渲染创建新组件
2. 重新挂载,丢失状态
3. 性能开销
错误示例:
function Parent() {
const Child = () => <div>Child</div>; // 错误!
return <Child />;
}
正确:
const Child = () => <div>Child</div>;
function Parent() {
return <Child />;
}58. 如何优化列表渲染?
答案:
优化方法:
1. 使用稳定key
2. 虚拟滚动
3. 分页/懒加载
4. React.memo包裹item
5. useCallback优化事件
示例:
const ListItem = React.memo(({ item, onClick }) => (
<div onClick={() => onClick(item.id)}>
{item.name}
</div>
));59. 什么是windowing?
答案:
定义: 虚拟滚动技术,只渲染可见项
库:
- react-window (轻量)
- react-virtualized (功能全)
使用场景:
- 超长列表
- 表格
- 无限滚动
示例:
<FixedSizeList
height={600}
itemCount={1000}
itemSize={35}
>
{Row}
</FixedSizeList>60. React.StrictMode的作用?
答案:
作用:
1. 检测不安全生命周期
2. 警告过时API
3. 检测副作用
4. 双重渲染检测
注意:
- 只在开发模式生效
- 会调用两次render
<StrictMode>
<App />
</StrictMode>React 19新特性 (61-80题)
61. React 19有哪些新特性?
答案:
1. React Compiler: 自动优化
2. Actions: 简化表单处理
3. use() Hook: 统一异步处理
4. Document Metadata: 原生title/meta
5. ref改进: ref作为普通prop
6. 资源预加载: 新的preload API62. Server Components是什么?
答案:
定义: 只在服务端运行的React组件
特点:
- 零客户端JavaScript
- 直接访问后端资源
- 减少bundle大小
- 不能使用Hooks
- 不能有交互
与SSR区别:
- SSR生成HTML
- RSC序列化组件树
- RSC不需要hydration63. React Compiler是什么?
答案:
定义: React 19自动编译优化工具
功能:
- 自动memoization
- 自动useCallback/useMemo
- 减少样板代码
- 性能自动优化
配置:
// babel.config.js
{
plugins: ['react-compiler']
}
优势:
- 无需手动优化
- 代码更简洁
- 性能提升64. Actions是什么?
答案:
定义: React 19简化表单处理的新特性
使用:
<form action={handleSubmit}>
<input name="username" />
<button type="submit">提交</button>
</form>
function handleSubmit(formData) {
const username = formData.get('username');
// 处理提交
}
配合Hooks:
- useFormStatus
- useFormState
- useOptimistic65. use() Hook是什么?
答案:
定义: 统一处理Promise和Context的Hook
使用:
// 读取Context
const theme = use(ThemeContext);
// 读取Promise
const data = use(fetchData());
特点:
- 可以在条件语句中使用
- 自动Suspense
- 统一异步处理66. useOptimistic的作用?
答案:
作用: 乐观更新UI
示例:
const [optimisticMessages, addOptimisticMessage] = useOptimistic(
messages,
(state, newMessage) => [...state, newMessage]
);
const handleSend = async (message) => {
addOptimisticMessage(message);
await sendMessage(message);
};
场景:
- 点赞
- 评论
- 表单提交67. useFormStatus是什么?
答案:
作用: 获取表单提交状态
使用:
function SubmitButton() {
const { pending } = useFormStatus();
return (
<button disabled={pending}>
{pending ? '提交中...' : '提交'}
</button>
);
}68. useFormState的使用?
答案:
作用: 管理表单状态和服务端反馈
使用:
const [state, formAction] = useFormState(serverAction, initialState);
<form action={formAction}>
<input name="email" />
{state.error && <p>{state.error}</p>}
</form>
async function serverAction(prevState, formData) {
// 验证和处理
return { error: null, success: true };
}69. Document Metadata如何使用?
答案:
定义: 在组件中直接设置title和meta
使用:
function BlogPost({ post }) {
return (
<>
<title>{post.title}</title>
<meta name="description" content={post.excerpt} />
<article>{post.content}</article>
</>
);
}
优势:
- 组件化
- 自动去重
- SSR友好70. ref作为prop有什么变化?
答案:
React 19:
- ref可以作为普通prop传递
- 不再需要forwardRef
之前:
const Input = forwardRef((props, ref) => (
<input ref={ref} {...props} />
));
现在:
function Input({ ref, ...props }) {
return <input ref={ref} {...props} />;
}71. 资源预加载API有哪些?
答案:
新API:
1. preload: 预加载资源
2. preinit: 预初始化资源
3. preconnect: 预连接
使用:
import { preload, preinit } from 'react-dom';
// 预加载脚本
preload('/script.js', { as: 'script' });
// 预初始化样式
preinit('/styles.css', { as: 'style' });
场景:
- 路由预加载
- 关键资源
- 第三方脚本72. Suspense有哪些改进?
答案:
React 19改进:
1. 支持data fetching
2. 更好的error boundary
3. Suspense列表
4. 嵌套Suspense优化
使用:
<Suspense fallback={<Loading />}>
<Component />
</Suspense>
配合:
- React.lazy
- use() Hook
- Server Components73. Error Boundary有哪些新特性?
答案:
React 19:
- 更好的错误信息
- error.digest支持
- 组件栈信息
使用:
class ErrorBoundary extends Component {
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
console.log(error.digest); // 新增
console.log(errorInfo.componentStack);
}
}74. hydration有什么改进?
答案:
改进:
1. 选择性hydration
2. 流式hydration
3. 错误恢复
4. 部分hydration
特点:
- 更快的交互
- 更好的用户体验
- 自动优先级75. Context有什么改进?
答案:
React 19改进:
1. 自动bailout优化
2. use()读取Context
3. 更好的性能
使用:
// 之前
const theme = useContext(ThemeContext);
// 现在
const theme = use(ThemeContext);
优势:
- 可以条件使用
- 更灵活76. 如何迁移到React 19?
答案:
迁移步骤:
1. 升级依赖
2. 移除forwardRef
3. 更新ref usage
4. 测试应用
注意事项:
- 检查breaking changes
- 更新第三方库
- 渐进式迁移77. React 19性能提升有哪些?
答案:
性能提升:
1. 自动优化(Compiler)
2. 更好的并发
3. 更少的JavaScript
4. 更快的hydration
测试结果:
- bundle大小减少30%
- 首屏速度提升40%
- 交互响应更快78. TypeScript支持有什么改进?
答案:
改进:
1. 更好的类型推导
2. ref类型简化
3. 泛型组件支持
4. Actions类型
示例:
function Input({ ref }: { ref: Ref<HTMLInputElement> }) {
return <input ref={ref} />;
}79. 测试React 19组件注意什么?
答案:
注意事项:
1. 测试Server Components
2. 测试use() Hook
3. 测试Actions
4. 测试并发特性
工具:
- @testing-library/react v15+
- jest
- vitest80. React 19最佳实践?
答案:
最佳实践:
1. 使用Server Components
2. 利用Compiler自动优化
3. 使用Actions简化表单
4. 用use()统一异步
5. 预加载关键资源
避免:
- 过度使用memo
- 手动优化(交给Compiler)
- 混用RSC和Client状态管理 (81-100题)
81. Redux的工作流程?
答案:
流程:
1. 组件dispatch action
2. action通过middleware
3. reducer处理action
4. 生成新state
5. 通知订阅者
6. 组件re-render
三大原则:
- 单一数据源
- State只读
- 纯函数修改82. Context和Redux的区别?
答案:
Context:
- React内置
- 简单易用
- 性能优化需手动
- 适合简单状态
Redux:
- 独立库
- 可预测性强
- 中间件支持
- 时间旅行调试
- 适合复杂应用83. Zustand的优势?
答案:
优势:
1. 轻量级(1KB)
2. 无样板代码
3. TypeScript友好
4. 无Context Provider
5. 支持middleware
使用:
const useStore = create((set) => ({
count: 0,
increment: () => set(state => ({ count: state.count + 1 }))
}));
场景:
- 中小型项目
- 简单全局状态84. Jotai和Recoil的区别?
答案:
Jotai:
- 更轻量
- API更简单
- 原子化
- 基于React Context
Recoil:
- Facebook开发
- 功能更全
- 异步支持好
- 更复杂
共同点:
- 原子化状态
- 细粒度更新
- 减少重渲染85. Redux Toolkit的优势?
答案:
优势:
1. 简化Redux配置
2. 内置Immer
3. RTK Query
4. 自动生成actions
5. 最佳实践
使用:
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: state => {
state.value += 1; // Immer自动处理
}
}
});86. RTK Query vs React Query?
答案:
RTK Query:
- 集成Redux
- 类型安全
- 强制规范
React Query:
- 独立库
- 更灵活
- 生态更好
- 社区更大
选择:
- 已用Redux -> RTK Query
- 新项目 -> React Query87. React Query的核心概念?
答案:
核心概念:
1. Queries: 数据获取
2. Mutations: 数据变更
3. Cache: 自动缓存
4. Refetch: 自动重新获取
5. Optimistic Updates: 乐观更新
使用:
const { data, isLoading } = useQuery({
queryKey: ['todos'],
queryFn: fetchTodos
});
优势:
- 自动缓存
- 后台刷新
- 重试机制88. SWR的特点?
答案:
特点:
1. stale-while-revalidate策略
2. 轻量级
3. 自动重新验证
4. 预加载
5. 乐观更新
使用:
const { data, error } = useSWR('/api/user', fetcher);
对比React Query:
- 更轻量
- API更简单
- 功能较少89. 状态管理库如何选择?
答案:
选择标准:
1. 项目规模
2. 团队熟悉度
3. 性能要求
4. TypeScript支持
5. 学习成本
推荐:
小型: Context + useState
中型: Zustand/Jotai + React Query
大型: Redux Toolkit + RTK Query
特殊: XState(状态机)90. 如何实现全局状态?
javascript
// 使用Zustand
import create from 'zustand';
const useGlobalStore = create((set) => ({
user: null,
theme: 'light',
setUser: (user) => set({ user }),
setTheme: (theme) => set({ theme })
}));
// 使用
function App() {
const { user, theme, setTheme } = useGlobalStore();
return <div>{theme}</div>;
}91. 如何实现状态持久化?
javascript
import create from 'zustand';
import { persist } from 'zustand/middleware';
const useStore = create(
persist(
(set) => ({
user: null,
setUser: (user) => set({ user })
}),
{
name: 'user-storage',
storage: localStorage
}
)
);92. 如何处理异步状态?
javascript
// 使用React Query
const { data, isLoading, error } = useQuery({
queryKey: ['user', id],
queryFn: () => fetchUser(id)
});
if (isLoading) return <Loading />;
if (error) return <Error />;
return <User data={data} />;93. 如何实现乐观更新?
javascript
const mutation = useMutation({
mutationFn: updateTodo,
onMutate: async (newTodo) => {
// 取消查询
await queryClient.cancelQueries({ queryKey: ['todos'] });
// 保存快照
const previousTodos = queryClient.getQueryData(['todos']);
// 乐观更新
queryClient.setQueryData(['todos'], old => [...old, newTodo]);
return { previousTodos };
},
onError: (err, newTodo, context) => {
// 回滚
queryClient.setQueryData(['todos'], context.previousTodos);
}
});94. 如何实现无限滚动?
javascript
const {
data,
fetchNextPage,
hasNextPage,
isFetchingNextPage
} = useInfiniteQuery({
queryKey: ['projects'],
queryFn: ({ pageParam = 0 }) => fetchProjects(pageParam),
getNextPageParam: (lastPage) => lastPage.nextCursor
});
// 监听滚动
const { ref } = useInView({
onChange: (inView) => {
if (inView && hasNextPage) {
fetchNextPage();
}
}
});95. 如何处理状态竞态?
javascript
function SearchComponent() {
const [query, setQuery] = useState('');
const { data } = useQuery({
queryKey: ['search', query],
queryFn: () => searchAPI(query),
enabled: query.length > 0,
// 自动取消旧请求
keepPreviousData: true
});
return (
<div>
<input value={query} onChange={e => setQuery(e.target.value)} />
{data?.results.map(item => <div key={item.id}>{item.name}</div>)}
</div>
);
}96. 如何实现状态派生?
javascript
// 使用Zustand
const useStore = create((set, get) => ({
items: [],
get totalPrice() {
return get().items.reduce((sum, item) => sum + item.price, 0);
},
get itemCount() {
return get().items.length;
}
}));
// 使用Recoil
const itemsState = atom({
key: 'items',
default: []
});
const totalPriceState = selector({
key: 'totalPrice',
get: ({ get }) => {
const items = get(itemsState);
return items.reduce((sum, item) => sum + item.price, 0);
}
});97. 如何处理表单状态?
javascript
// 使用React Hook Form
import { useForm } from 'react-hook-form';
function Form() {
const { register, handleSubmit, formState: { errors } } = useForm();
const onSubmit = (data) => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('username', { required: true })} />
{errors.username && <span>必填</span>}
<button type="submit">提交</button>
</form>
);
}98. 如何实现状态同步?
javascript
// 多Tab同步
const useStore = create(
persist(
(set) => ({
count: 0,
increment: () => set(state => ({ count: state.count + 1 }))
}),
{
name: 'count-storage',
onRehydrateStorage: () => (state) => {
// 监听storage变化
window.addEventListener('storage', (e) => {
if (e.key === 'count-storage') {
// 同步状态
}
});
}
}
)
);99. 如何测试状态管理?
javascript
// 测试Zustand Store
import { renderHook, act } from '@testing-library/react';
import { useStore } from './store';
describe('Store', () => {
it('should increment', () => {
const { result } = renderHook(() => useStore());
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});
});
// 测试React Query
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
const wrapper = ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
);
it('should fetch data', async () => {
const { result } = renderHook(() => useUsers(), { wrapper });
await waitFor(() => expect(result.current.isSuccess).toBe(true));
expect(result.current.data).toBeDefined();
});100. 面试总结和建议
答案:
准备建议:
1. 掌握核心原理
2. 熟悉常用Hooks
3. 了解性能优化
4. 实践项目经验
5. 关注最新特性
6. 练习手写代码
面试技巧:
1. 理解题意
2. 分析思路
3. 清晰表达
4. 编码规范
5. 考虑边界
6. 优化改进总结
100道React面试题涵盖:
- 基础概念: JSX、组件、Props/State
- Hooks: useState、useEffect、useMemo等
- 性能优化: memo、虚拟滚动、代码分割
- React 19: 新特性和变化
- 状态管理: Redux、Context、Zustand
- 实战经验: 项目架构、问题解决
全面掌握这些题目可以应对大部分React面试。