版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
高频react面试题及答案1.类组件中setState是同步还是异步?为什么会有这样的表现?在哪些情况下是同步的?setState在类组件中默认表现为异步更新,这是React为了优化性能做的批量更新策略。React会将多个setState调用合并为一次更新,减少重新渲染的次数。其异步性体现在:调用setState后无法立即获取更新后的state值,需要通过回调函数(setState的第二个参数)或componentDidUpdate生命周期来获取最新状态。但setState的“异步”并非绝对,其行为依赖于调用它的上下文环境:在React管理的事件处理函数(如onClick、onChange)中,setState是异步的。因为React会将事件处理内的所有setState收集起来,在事件结束时批量更新。在原生事件(如addEventListener绑定的事件)、setTimeout/setInterval、Promise回调等非React管理的上下文中,setState会表现为同步更新。因为这些场景中React无法感知到批量更新的时机,会立即执行更新逻辑。例如,在setTimeout中调用setState时,由于定时器回调由浏览器的任务队列管理,React无法在定时器回调执行时合并更新,因此会立即触发重新渲染,此时setState表现为同步。2.React生命周期函数的执行顺序是怎样的?16.3版本后新增的getDerivedStateFromProps和getSnapshotBeforeUpdate有什么作用?经典类组件(React16.3前)的生命周期分为挂载、更新、卸载三个阶段:挂载阶段:constructor→componentWillMount(已废弃)→render→componentDidMount更新阶段:componentWillReceiveProps(已废弃)→shouldComponentUpdate→componentWillUpdate(已废弃)→render→componentDidUpdate卸载阶段:componentWillUnmountReact16.3引入Fiber架构后,为了支持异步渲染(ConcurrentMode),废弃了componentWillMount、componentWillReceiveProps、componentWillUpdate这三个“will”开头的生命周期(标记为UNSAFE_前缀),新增了getDerivedStateFromProps和getSnapshotBeforeUpdate:getDerivedStateFromProps(静态方法):在组件挂载或更新时,当props变化时被调用。它接收当前props和prevState,返回一个对象用于更新state,或返回null表示不更新。主要用于替代componentWillReceiveProps,避免因异步更新导致的副作用问题。例如,当父组件传递的props变化时,需要根据新props更新组件内部state的场景。getSnapshotBeforeUpdate(实例方法):在render之后、DOM更新之前被调用。它可以获取更新前的DOM状态(如滚动位置),返回的快照值会作为参数传递给componentDidUpdate。典型用途是在列表项更新时,保持滚动位置不变:通过记录更新前的滚动高度,在componentDidUpdate中调整滚动条位置。完整的新生命周期顺序(挂载时):constructor→staticgetDerivedStateFromProps→render→componentDidMount更新时(props/state变化或forceUpdate):staticgetDerivedStateFromProps→shouldComponentUpdate→render→getSnapshotBeforeUpdate→componentDidUpdate3.函数组件中useState的setter函数是同步还是异步?与类组件的setState有何区别?useState的setter函数在行为上与类组件的setState类似,默认表现为异步更新,但实现机制不同。在React事件处理或hooks回调中,setter函数不会立即更新state,而是将更新加入队列,等待批量处理。例如,在点击事件中连续调用两次setCount(count+1),最终count只会增加1,因为两次更新基于同一个初始值。区别在于:类组件的setState可以接收对象或函数((prevState,props)=>newState),而useState的setter可以接收新值或函数((prev)=>new)。使用函数形式可以确保获取到最新的state,避免闭包陷阱。例如,在异步回调中调用setter时,函数形式能保证基于最新状态计算。类组件的setState可能触发组件更新(除非shouldComponentUpdate返回false),而函数组件中useState的更新总是会触发重新渲染(除非组件被React.memo包裹且props未变化)。类组件的setState支持批量更新的范围更广(如同一事件内的多个setState合并),而函数组件中若在同一个事件循环中多次调用不同useState的setter,React也会合并为一次渲染。4.React的虚拟DOM(VirtualDOM)是如何工作的?diff算法的核心规则是什么?虚拟DOM是真实DOM的轻量级JavaScript对象表示,包含标签名、属性、子节点等信息。其核心作用是通过比较两次渲染的虚拟DOM树差异(diff),仅更新真实DOM中变化的部分,减少直接操作DOM的性能消耗(DOM操作成本远高于JS计算)。React的diff算法遵循以下核心规则以降低复杂度(时间复杂度从O(n³)优化到O(n)):同级比较:只比较同一层级的节点,不会跨层级移动节点。若节点在不同层级出现,会直接卸载旧节点并挂载新节点。键(key)优化:对于列表项,通过唯一key标识节点。当列表顺序变化时,React根据key匹配新旧节点,避免重新创建未变化的节点。若未提供key,React默认按索引匹配,可能导致错误更新(如插入新项时后续项的索引变化,引发不必要的重新渲染)。类型判断:当节点类型(如div→p)或组件类型(如ComponentA→ComponentB)变化时,React会卸载旧节点并挂载新节点。若类型相同,仅更新属性和子节点。例如,当列表项顺序变化时,正确的key可以让React识别到节点只是位置变化,只需调整DOM位置;而无key时,React会认为每个索引对应的节点都发生了变化,导致所有节点重新渲染。5.如何优化React组件的性能?常见的优化手段有哪些?React性能优化的核心是减少不必要的重新渲染,主要手段包括:避免父组件状态变化导致子组件不必要的渲染:类组件:使用PureComponent(浅比较props和state)或手动实现shouldComponentUpdate(对比变化的属性)。函数组件:使用React.memo包裹组件(浅比较props),配合useMemo缓存计算结果,useCallback缓存回调函数(避免父组件重新渲染时提供新的函数引用,导致子组件重新渲染)。优化状态管理:将状态提升到最近的公共父组件,避免深层嵌套组件因上层状态变化而重新渲染。使用状态分片(如多个useState代替单个对象状态),仅当相关状态变化时触发渲染。减少渲染逻辑中的计算量:用useMemo缓存昂贵的计算结果(如列表过滤、数据格式化),仅当依赖项变化时重新计算。避免在render函数中定义对象或函数(如onClick={()=>handleClick()}),这会导致每次渲染提供新的引用,触发子组件重新渲染。使用React.lazy和Suspense实现代码分割:对非首屏组件使用动态导入(import()),配合Suspense显示加载状态,减少首屏加载时间。利用Fiber架构的特性:React18的ConcurrentMode(并发模式)通过优先级调度,允许低优先级任务(如非紧急UI更新)中断,优先处理高优先级任务(如用户输入),提升响应速度。避免直接操作真实DOM:尽量使用React的状态管理来更新UI,减少手动调用getElementById等原生DOM操作,因为这会绕过虚拟DOM的diff过程,可能导致状态与DOM不同步。6.解释React的事件机制。为什么说React事件是合成事件?与原生事件有何区别?React事件是对原生DOM事件的封装,称为“合成事件”(SyntheticEvent)。它遵循W3C标准,提供与原生事件相同的接口(如stopPropagation、preventDefault),但内部实现不同:合成事件的特点:事件委托:React不会为每个DOM元素单独绑定事件监听器,而是将所有事件绑定到根DOM节点(如<divid="root">),通过事件冒泡机制统一处理。这样可以减少内存占用,提升性能。跨浏览器兼容:对不同浏览器的事件行为进行标准化(如IE的event对象获取方式),开发者无需处理浏览器差异。事件对象池化:合成事件对象(SyntheticEvent)会被复用,在事件处理函数执行后,所有属性会被置为null(或放回池中)。若需要异步访问事件对象,需调用event.persist()方法保留引用。与原生事件的区别:绑定方式:React事件使用驼峰命名(如onClick),原生事件使用全小写(如onclick);React事件通过JSX属性传递,原生事件通过addEventListener或DOM属性绑定。事件传播:React的事件冒泡机制在合成事件系统中完成,与原生事件的冒泡是两个独立的流程。例如,在React事件处理函数中调用event.stopPropagation()只会阻止合成事件的冒泡,不会影响原生事件的冒泡;若要同时阻止原生事件,需手动调用event.nativeEvent.stopPropagation()。执行顺序:当同一个DOM元素同时绑定React事件和原生事件时,原生事件的监听器会先执行,React合成事件后执行(因为React的事件委托是在原生事件冒泡到根节点时触发)。7.什么是Fiber架构?它解决了什么问题?核心设计思想是什么?Fiber是React16引入的新协调器(Reconciler)的底层数据结构,用于替代React15的StackReconciler。其核心目标是解决复杂应用中长任务导致的页面卡顿问题(如JS执行时间过长阻塞UI渲染和用户输入)。StackReconciler的问题:采用递归方式进行虚拟DOM的diff计算,一旦开始就无法中断。当组件树很深时,递归调用栈可能超过16ms(浏览器一帧的时间),导致页面掉帧,用户体验卡顿。Fiber架构的核心设计思想是“可中断的协作式调度”:将调和(Reconciliation)过程拆分为多个小任务(work),每个任务执行一段时间后(如5ms),主动让出JS执行权给浏览器(通过requestIdleCallback或MessageChannel),优先处理用户输入、动画等紧急任务,之后再恢复未完成的任务。Fiber的实现基于“链表”结构:每个Fiber节点代表一个组件、DOM节点或其他类型的节点,保存了组件的状态、props、子节点等信息。通过child、sibling、return指针形成树状链表,使得调和过程可以从任意节点中断和恢复。关键特性:任务优先级:每个任务被赋予不同优先级(如用户输入触发的更新优先级高于数据加载),高优先级任务可以中断低优先级任务。双缓存机制:维护当前渲染的Fiber树(currenttree)和正在计算的Fiber树(workInProgresstree),计算完成后通过替换根节点(commit阶段)将workInProgress树变为current树,保证渲染的原子性。增量更新:将diff过程分解为多个步骤,逐步更新,避免长时间阻塞主线程。8.useRef有哪些常见用途?与useState的区别是什么?useRef是React提供的一个hook,返回一个可变的ref对象,其current属性可以保存任意值,且在组件生命周期内保持引用不变。常见用途包括:访问DOM元素:通过ref属性绑定到组件或DOM节点,如constinputRef=useRef();<inputref={inputRef}/>,之后可通过inputRef.current获取DOM节点。保存可变的状态:如定时器ID、第三方库实例等需要在多次渲染间保持的非UI状态。因为useState的更新会触发重新渲染,而useRef的current属性变化不会触发渲染。解决闭包陷阱:在异步回调中获取最新的state或props值。例如,在setTimeout中若直接使用旧的state,可通过ref保存最新值,回调中访问ref.current获取最新状态。与useState的区别:数据类型:useState保存的是响应式状态(state变化触发重新渲染),而useRef保存的是非响应式数据(current变化不触发渲染)。更新方式:useState通过setter函数更新,而useRef直接修改current属性(如ref.current=newValue)。用途:useState用于管理UI相关的状态(如按钮是否激活、列表数据),useRef用于管理与渲染无关的可变数据或DOM引用。9.React中如何实现跨组件通信?常见的解决方案有哪些?跨组件通信指非父子关系的组件(如兄弟、祖孙、跨层级组件)之间的状态共享,常见方案包括:状态提升(LiftingStateUp):将共享状态提升到最近的公共父组件,通过props传递状态和修改状态的函数。适用于层级较浅的组件树,如兄弟组件通信。例如,兄弟组件A和B需要同步输入内容,可将输入值保存在父组件,通过onChange回调更新父组件状态,再传递给A和B。上下文(Context):使用React.createContext创建上下文对象,通过Provider组件传递状态,子组件通过useContext(函数组件)或Context.Consumer(类组件)获取状态。适用于深层嵌套组件的状态共享(如主题、用户登录信息)。需注意:Context的更新会触发所有消费该Context的组件重新渲染,因此需合理设计Context的粒度(避免将频繁变化的状态放入同一个Context)。状态管理库(如Redux、MobX):适用于复杂应用的全局状态管理。Redux通过单一store保存状态,通过action触发reducer更新状态,组件通过connect或useSelector获取状态,useDispatch发送action。MobX通过可观察(observable)状态和观察者(observer)组件实现自动响应。事件总线(EventBus):通过全局的事件订阅/发布机制实现通信。例如,使用自定义的EventEmitter类,组件A发布事件,组件B订阅事件并执行回调。需注意内存泄漏问题(组件卸载时需取消订阅)。第三方库(如Zustand、Jotai):轻量级状态管理库,适合中小型应用。Zustand通过create函数创建store,组件通过useStore钩子订阅特定状态,仅当订阅的状态变化时重新渲染。10.React18的新特性有哪些?ConcurrentMode带来了哪些改进?React18的核心新特性包括:自动批处理(AutomaticBatching):在更多场景下自动合并状态更新(如Promise、setTimeout、原生事件回调),减少不必要的重新渲染。例如,在Promise的then回调中调用多个setState,React会合并为一次渲染(React18前需手动用flushSync包裹)。新的rootAPI:使用createRoot替代ReactDOM.render(如constroot=createRoot(container);root.render(<App/>)),支持并发特性。并发渲染(ConcurrentRendering):基于Fiber架构的ConcurrentMode成为默认模式,允许组件树的不同部分以不同优先级渲染。关键特性包括:SuspenseforDataFetching:支持在数据加载时显示加载状态(如<Suspensefallback={<Loading/>}><Component/></Suspense>),并允许组件树的一部分先渲染,其他部分在数据准备好后逐步加载。过渡(Transitions):通过useTransition或startTransition标记非紧急更新(如搜索结果过滤),允许高优先级任务(如用户输入)中断低优先级的过渡更新,避免界面卡顿。例如:const[isPending,startTransition]=useTransition();startTransition(()=>{setSearchQuery(inputValue);//低优先级更新});流式服务端渲染(StreamingSSR):服务端可以逐步发送HTML片段,配合客户端的hydration(水合),提升首屏加载速度。新的hooks:useId:提供全局唯一的ID,适用于服务端渲染场景(避免客户端和服务端ID不一致)。useSyncExternalStore:用于安全地订阅外部状态(如Reduxstore),解决并发模式下的hydration问题。useInsertionEffect:主要用于CSS-in-JS库,在DOM插入前执行副作用(如注入样式),避免布局抖动。ConcurrentMode的核心改进是提升应用的响应性,通过优先级调度和可中断的渲染,确保用户输入、动画等关键任务优先执行,避免长任务阻塞主线程。例如,用户输入时,输入处理的高优先级任务可以中断正在进行的低优先级渲染任务,用户不会感受到延迟;输入完成后,被中断的渲染任务继续执行,更新界面。11.什么是React的memoization?常用的memoization工具(如React.memo、useMemo、useCallback)有何区别?Memoization(记忆化)是一种缓存技术,用于避免重复计算相同的输入结果。在React中,主要用于避免组件或计算的不必要重新执行。常用工具及区别:React.memo:高阶组件,用于缓存函数组件的渲染结果。它浅比较前后两次渲染的props,若props未变化则复用上次渲染结果,避免重新调用组件函数。默认浅比较,可通过第二个参数自定义比较函数((prevProps,nextProps)=>boolean)。适用于纯组件(渲染结果仅依赖props)。useMemo:hook,用于缓存计算结果。它接收一个计算函数和依赖数组,仅当依赖项变化时重新计算。返回缓存的值。适用于缓存昂贵的计算(如列表排序、数据过滤),避免每次渲染都重新计算。useCallback:hook,用于缓存函数引用。它接收一个函数和依赖数组,仅当依赖项变化时返回新的函数引用。适用于缓存传递给子组件的回调函数,避免父组件重新渲染时提供新的函数引用,导致子组件(被React.memo包裹)不必要的重新渲染。三者的核心区别在于应用场景:React.memo缓存组件渲染结果,useMemo缓存计算值,useCallback缓存函数引用。例如,当父组件传递一个回调函数给子组件时,若父组件重新渲染,未使用useCallback会导致回调函数引用变化,子组件即使props其他属性未变也会重新渲染;使用useCallback后,只要依赖项未变,回调函数引用不变,子组件可跳过渲染。12.解释React中的“key”属性的作用。为什么推荐使用稳定、唯一的key?key是React用于标识列表项的特殊属性,帮助React在diff过程中快速识别哪些项被添加、删除或重新排序。其核心作用是:优化diff算法:通过key匹配新旧虚拟DOM中的节点,避免重新创建未变化的节点,减少DOM操作。保持组件状态:当列表项顺序变化时,React根据key关联组件实例,确保组件的状态(如输入框内容、滚动位置)与正确的项绑定。推荐使用稳定、唯一的key的原因:唯一性:确保每个兄弟节点的key不同,避免React无法正确识别节点(可能导致渲染错误或状态混乱)。稳定性:避免使用索引(index)作为key(除非列表顺序固定且不会增删项)。例如,当列表插入新项时,后续项的索引会变化,导致key变化,React会认为这些项被替换,重新创建组件实例,丢失原有状态。例如,以下列表使用索引作为key存在隐患:constlist=items.map((item,index)=><Itemkey={index}{...item}/>);当在列表头部插入新项时,原第一项的索引从0变为1,React会认为原第一项被删除,新项插入,原第二项变为新的第一项(索引0),导致组件状态错误关联。正确做法是使用数据中唯一且稳定的标识符(如数据库ID、UUID)作为key:constlist=items.map(item=><Itemkey={item.id}{...item}/>);13.函数组件中如何处理副作用?useEffect的依赖数组有什么作用?常见的误用场景有哪些?副作用(SideEffects)指与渲染无关的操作,如数据获取、事件监听、定时器、修改外部变量等。函数组件中通过useEffect处理副作用,其语法为useEffect(effect,dependencies)。依赖数组的作用是控制effect的执行时机:空数组([]):effect仅在组件挂载(首次渲染)后执行,卸载时执行清理函数(若effect返回函数)。适用于只需要执行一次的副作用(如初始化数据获取)。包含依赖项([a,b]):effect在组件挂载后、依赖项(a或b)变化时执行。适用于依赖props或state的副作用(如根据props.id获取数据)。无依赖数组(省略):effect在每次组件渲染后执行。适用于需要实时响应的副作用(如监听窗口大小变化)。常见误用场景:遗漏必要的依赖项:若effect中使用了组件状态(state)、props或其他组件内的变量,需将其加入依赖数组。否则,effect可能使用旧值,导致逻辑错误。例如:functionComponent(){const[count,setCount]=useState(0);useEffect(()=>{consttimer=setInterval(()=>{setCount(count+1);//错误:count是闭包中的旧值,每次interval回调使用初始的count=0},1000);return()=>clearInterval(timer);},[]);//缺少依赖count,导致timer中的count不更新}正确做法是使用函数形式的setCount(setCount(c=>c+1)),或在依赖数组中加入count(但会导致每次count变化时重新创建timer)。不必要的依赖项:将稳定的值(如不会变化的函数、对象)加入依赖数组,导致effect频繁执行。例如,若handleClick函数未使用任何组件状态或props,可通过useCallback缓存,避免其引用变化触发effect重新执行。清理函数未正确处理:effect返回的清理函数应取消未完成的异步操作(如abortcontroller取消fetch请求)、移除事件监听等,避免内存泄漏。例如,若effect中订阅了事件,未在清理函数中移除监听,组件卸载后事件仍会触发,导致错误。14.React中如何实现服务端渲染(SSR)?与客户端渲染(CSR)相比有什么优势
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年理解春节的团圆与情感共鸣
- 2026年保险产品精准营销策略培训
- 2025年山东省事业编四月底笔试及答案
- 2025年广东护理事业编考试试题及答案
- 2025年陕西省渭南市人事考试及答案
- 2026年小兔的春节家庭聚会
- 2025年思明幼教笔试及答案
- 2025年老八校建筑学复试笔试题及答案
- 2025年物联网面试笔试题及答案
- 2025年生物初中教资笔试及答案
- 绿化养护验收实施方案1
- 2024年理财行业高质量发展白皮书-农银理财
- 危险化学品经营单位(安全生产管理人员)考试题及答案
- UL498标准中文版-2019插头插座UL标准中文版
- 《非物质文化遗产》课程教学大纲
- 小学英语名师工作室工作总结
- (高清版)DZT 0210-2020 矿产地质勘查规范 硫铁矿
- 居民自建桩安装告知书回执
- QC080000体系内部审核检查表
- 初中语文仿写训练
- 延迟焦化装置(改)
评论
0/150
提交评论