京东-技术中台-校招 · 第 1 轮 · 二面

← 第 1 轮 · 返回本次面经 · 已是最后一轮 → 本轮要点: 本次面试聚焦CSS布局核心问题(浮动清除、BFC机制)、高频JS手写能力(防抖函数)、工程化实践(TS迁移痛点、Vue3升级策略)、深度性能优化(缓存协同更新、Tree Shaking原理)。难点在于浮动导致的布局塌陷解决方案、CDN与本地缓存协同策略设计,以及复杂框架迁移的兼容性处理。 本轮共 11 道题。答案默认折叠,便于先自行作答。 1. 浮动元素导致的布局错乱应该如何解决? 题目要点 CSS浮动布局及解决方案。 参考答案 浮动元素会导致其父元素高度塌陷,从而影响布局。解决方法有: 1. 清除浮动:在浮动元素后面添加一个空的`div`,设置`clear: both`。 2. 使用伪元素清除浮动:在父元素上使用`::after`伪元素,设置`clear: both`。 .parent::after { content: ""; display: block; clear: both; } 1. 使用`overflow: hidden`:给父元素设置`overflow: hidden`,但可能会隐藏超出部分的内容。 2. 使用`BFC`(块级格式化上下文):通过设置`display: flow-root`或`overflow: auto`等属性,使父元素形成一个独立的BFC,从而包含浮动元素。 2. 实现一个固定侧边栏+自适应主内容的布局 题目要点 CSS布局技巧。 参考答案 可以使用flexbox布局实现固定侧边栏和自适应主内容的布局: <div class="container"> <div class="sidebar">侧边栏</div> <div class="main">主内容</div> </div> .container { display: flex; } .sidebar { width: 200px; /* 固定宽度 */ background-color: #f0f0f0; } .main { flex: 1; /* 自适应宽度 */ background-color: #ffffff; } 3. 实现 debounce(防抖)函数 题库原题:实现 debounce(防抖)函数 ...

June 27, 2025

京东-技术中台-校招 · 第 1 轮 · 一面

← 已是第一轮 · 返回本次面经 · 第 1 轮 → 本轮要点: 本次面试深度考察JavaScript核心原理(闭包、继承实现)、前端框架(Vue响应式机制、虚拟DOM性能、Vue vs React区别)、性能优化(高并发请求处理、HTTP/2应用)、前端安全(XSS/CSRF防御)。难点聚焦于Vue响应式系统限制的解决(如动态字段更新)、复杂布局实现(自适应流式),以及高效算法设计(O(n)去重)。 本轮共 14 道题。答案默认折叠,便于先自行作答。 1. 自我介绍 题目要点 个人背景、能力、经验。 参考答案 我叫[姓名],毕业于[学校],专业是[专业]。我有[X]年的前端开发经验,熟练掌握HTML、CSS、JavaScript等前端技术,熟悉Vue.js和React框架。在项目中,我注重代码质量和用户体验,善于解决复杂的技术问题。我曾参与过多个大型项目的开发,例如[项目名称],负责[具体工作],通过优化代码结构和性能,提升了页面加载速度和用户体验。 2. 怎么学习javascript的?讲一下闭包,自己的使用场景 题目要点 JavaScript学习方法、闭包概念及应用。 参考答案 学习JavaScript时,我首先从基础语法入手,通过阅读经典书籍如《JavaScript高级程序设计》来系统地学习。闭包是JavaScript中的一个重要概念,它允许函数记住并访问其创建时所在的作用域链中的变量。闭包的使用场景很多,比如在事件处理中,可以使用闭包来保存事件相关的数据。例如,创建一个计数器函数,每次调用时返回当前的计数值,利用闭包可以保持计数器的状态。 3. Javascript如何实现继承? 题库原题:Javascript如何实现继承? 题目要点 1. 原型链继承 通过将一个构造函数的实例作为另一个构造函数的原型,实现属性和方法的继承。 特点 简单易实现。 缺点是父类实例的属性会被所有子类实例共享。 2. 借用构造函数(经典继承) 通过在子类构造函数中调用父类构造函数,实现属性的继承。 特点 避免了原型链继承共享属性的问题。 但无法继承父类的原型方法。 3. 组合继承(原型链+借用构造函数) 结合原型链继承和借用构造函数的方法,既调用父类构造函数,又将父类原型赋值给子类原型。 特点 可以继承实例属性和原型方法。 需要注意避免构造函数属性的多次调用。 4. 原型式继承 使用一个函数来创建一个新对象,并将这个新对象的原型指向另一个对象。 特点 适用于对象之间的属性继承,不涉及构造函数。 5. 寄生式继承 基于原型式继承,但添加了额外的包装函数,以提供更好的控制和灵活性。 特点 通过创建对象的副本来实现继承,避免修改原始对象。 6. ES6 类继承 使用class关键字和extends关键字实现继承。 特点 语法简洁,易于理解。 底层仍然是基于原型链实现。 参考答案 一、是什么 继承(inheritance)是面向对象软件技术当中的一个概念。 如果一个类别B“继承自”另一个类别A,就把这个B称为“A的子类”,而把A称为“B的父类别”也可以称“A是B的超类” 继承的优点 继承可以使得子类具有父类别的各种属性和方法,而不需要再次编写相同的代码 ...

June 27, 2025

京东-广告数据-校招 · 第 1 轮 · 一面

← 已是第一轮 · 返回本次面经 · 已是最后一轮 → 本轮要点: 考察核心集中在前端性能优化(如无限加载卡顿、页面渲染延迟)、CSS布局与兼容性(如Flexbox自适应、跨浏览器适配)及Vue框架原理(如响应式限制、虚拟DOM优劣)。需重点准备懒加载/虚拟滚动优化、兼容性Hack技巧、异步执行顺序分析及需求拆分设计能力。 本轮共 12 道题。答案默认折叠,便于先自行作答。 1. 现在我们有一个 618 活动页的需求,需要你来做,你会如何拆分需求,如何设计? 题目要点 需求分析与设计能力 参考答案 首先与产品、设计、运营等多部门沟通,明确活动页的核心功能、促销规则、页面风格等基本需求。例如,确定活动主题(如限时秒杀、满减优惠等)、预计流量、商品展示形式等。 根据功能模块拆分需求,可将活动页分为头部导航区(包含活动标题、时间、入口等信息)、商品展示区(如秒杀商品列表、热门推荐商品列表等)、促销信息区(展示活动规则、优惠券领取等)、底部信息区(如活动说明、客服入口等)。 在设计上,根据品牌风格和活动主题确定整体视觉风格,包括配色方案(如节日氛围的红色、金色等)、字体选择、图片风格等。针对商品展示区,考虑采用网格布局或瀑布流布局,以合理展示商品信息,包括商品图片、名称、价格、优惠信息等。对于交互设计,需考虑页面的滚动加载、商品点击跳转、优惠券领取等交互效果,确保用户体验流畅。 2. 商品列表中一行有五个商品卡片,最后一个自适应剩余空间,怎么实现。 题目要点 CSS 布局能力 参考答案 可以使用 CSS 的 Flexbox 布局来实现。首先将商品列表的容器设置为 flex 布局,即 display: flex。然后对前四个商品卡片设置固定宽度,例如 width: 100px,最后一个商品卡片设置 flex: 1,这样它就会占据所在行剩余的空间,实现自适应效果。同时,为了防止一行中商品卡片因内容过多而超出父容器宽度,可对每个商品卡片设置 overflow: hidden,确保其内容在自身区域内显示,并且可以添加 white - space: nowrap 和 text - overflow: ellipsis 来处理溢出的文字内容。 3. CSS 样式开发中你都遇到过哪些兼容性问题,如何解决的。 题目要点 CSS 问题解决能力及兼容性知识 参考答案 在不同浏览器中遇到过盒模型问题,例如 IE 浏览器的怪异盒模型与其他浏览器的标准盒模型不同,导致元素尺寸计算不一致。解决方法是使用 box - sizing: border - box,并结合 CSS 重置样式表统一各浏览器的盒模型表现。 2. 浮动布局在某些低版本浏览器中可能出现父元素高度塌陷或子元素排列不整齐的问题。可以通过为父元素添加 clearfix 清除浮动,即设置父元素 overflow: hidden 或使用伪元素 :after 添加清除浮动的样式来解决。 3. CSS3 动画在部分浏览器中可能不支持,或者动画效果不一致。例如,IE 浏览器对 CSS3 动画的支持较弱。解决方法是使用渐进增强的方式,在支持 CSS3 动画的浏览器中展示动画效果,对于不支持的浏览器提供简单的过渡效果或静态样式,并利用Modernizr 等工具进行特性检测,根据检测结果加载相应的样式和脚本。 4. 字体渲染在不同操作系统和浏览器中可能存在差异,影响页面的美观和一致性。可以通过设置字体的 font - family 为系统安全字体组合,并使用相对单位(如 em、rem)设置字体大小,以提高字体的兼容性和可读性。 4. 你刚刚说的上滑无限加载有没有性能问题,你怎么解决? 题目要点 前端性能优化知识 ...

June 27, 2025

字节-飞书-校招 · 第 1 轮 · 二面

← 第 1 轮 · 返回本次面经 · 已是最后一轮 → 本轮要点: 本次面试主要考察前端开发者的项目经验、技术深度、问题解决能力以及对未来发展的思考。 本轮共 15 道题。答案默认折叠,便于先自行作答。 1. 了解飞书么,讲一下你的使用感受 题目要点 ● 说明该题是主观型问题,不考"唯一标准答案" ● 面试官主要考察答题者对产品的理解、用户体验的洞察以及归纳总结能力 ● 答题结构建议:首先简要说明你对飞书的整体印象和使用频率,然后从几个具体的产品功能或使用场景出发,详细阐述你的感受、亮点和可以改进的地方。 参考答案 高质量参考范文: 我对飞书这款产品有比较深入的了解,因为我们团队在日常工作中就是飞书的重度用户,几乎所有的协作和沟通都在上面进行。从我的使用感受来看,飞书在一体化协作方面做得非常出色,它不仅仅是一个简单的即时通讯工具,更是一个集成了文档、会议、日程、OKR、邮件等多种功能的综合性协作平台,极大地提升了团队的工作效率。 我感受最深的有以下几点: 首先是文档和表格的强大协作能力。飞书文档支持多人实时协同编辑,光标跟随、评论批注等功能都非常流畅,我们团队经常用它来共同撰写需求文档、项目周报等。表格功能也比传统Excel更灵活,支持多种视图和自动化能力,对于项目管理和数据统计非常方便,我们很多内部管理工作都迁移到了飞书表格上。这种所见即所得、实时同步的体验,比我们之前使用分离的工具效率高出很多。 其次是会议和日历的无缝整合。飞书会议的音视频质量很高,屏幕共享和标注功能也很实用。最棒的是它和日历的深度集成,我们可以在日历中直接创建会议,并关联飞书文档,会议结束后纪要也能快速生成并同步。这种从会议发起、进行到纪要归档的全流程一体化体验,减少了大量来回切换应用的麻烦。 当然,在使用过程中,我也注意到一些可以改进的地方。例如,对于一些复杂的数据可视化需求,飞书表格目前的图表功能可能还不够强大,我们有时需要导出数据到其他专业工具进行处理。另外,在面对外部协作场景时,虽然飞书支持分享外部链接,但在权限控制和安全性方面,如果能提供更多灵活的配置选项,会更便于与外部伙伴高效协同。 总的来说,飞书极大地改变了我们团队的协作模式,提升了整体工作效率。它在集成化、实时协作和移动端体验方面都有着显著优势。我相信随着产品的不断迭代,它在更多细分场景和个性化需求方面会做得更好。 2. 如果飞书的某一个页面崩溃了 ,你会如何处理? 题目要点 ● 说明该题是主观型问题,不考"唯一标准答案" ● 面试官主要考察答题者的故障排查能力、问题分析思路、应急处理流程以及对用户体验的关注 ● 答题结构建议:首先表明你会从用户角度出发,然后从前端排查、后端排查、联调分析、解决方案、预防措施等多个维度,阐述你处理问题的完整思路和步骤。 参考答案 高质量参考范文: 如果飞书的某个页面崩溃了,我会立即启动一套系统的故障排查和处理流程,目标是尽快定位问题、恢复服务,并最大程度地减少对用户的影响。 我的处理思路和步骤通常如下: 初步判断与用户安抚(P0 紧急): 确认问题范围: 首先,我会尝试复现问题,看是偶发性还是普遍性,是个别用户遇到还是所有用户,是特定浏览器或环境下崩溃,还是全量崩溃。这决定了问题的优先级和后续排查方向。 快速截图/录屏: 立即保留现场证据,包括控制台报错、网络请求、崩溃页面截图等,为后续分析提供依据。 安抚用户/上报: 如果是线上普遍性问题,会第一时间通过内部渠道(如即时通讯工具)向上级和相关团队(后端、产品、SRE等)同步情况,并考虑是否需要发布公告,引导用户刷新页面或使用其他临时方案,确保用户感受到问题正在被处理。 前端层面排查: 控制台日志分析: 检查浏览器开发者工具的Console面板,查看是否有JavaScript错误、警告或网络请求失败的提示。JavaScript报错通常是页面崩溃的直接原因,栈追踪能帮助定位代码位置。 网络请求分析: 检查Network面板,看是否有接口请求失败(如4XX、5XX错误),或者请求超时。特别是5XX错误,可能指示后端服务异常导致页面无法获取必要数据而崩溃。 内存与CPU占用: 使用Performance和Memory面板,观察页面崩溃前是否有内存飙升或CPU占用过高的情况,这可能指向内存泄漏、死循环或计算密集型操作。 代码回溯与版本: 确认当前页面的代码版本,检查近期是否有相关代码上线,是否有回滚的必要。使用Source面板进行断点调试,观察变量值和代码执行流程。 本地存储检查: 检查LocalStorage、SessionStorage和IndexedDB,看是否有脏数据或超大存储导致的问题。 后端及服务层面排查(与后端协作): 接口健康状况: 如果前端排查怀疑是后端问题,我会联系后端开发或SRE团队,确认相关API接口的健康状况、服务日志、异常报警信息。 数据库或缓存: 后端会进一步排查数据库连接、缓存服务是否正常,是否有慢查询或数据一致性问题。 依赖服务: 检查该页面所依赖的微服务或其他第三方服务是否正常运行。 定位与解决方案: 锁定问题点: 根据排查结果,确定是前端代码Bug(如空指针、死循环、组件渲染异常)、后端接口问题、网络问题、兼容性问题,还是其他服务故障。 制定方案: 如果是前端Bug,立即着手修复,并进行单元测试和集成测试。如果是后端问题,协同后端团队修复。如果是数据问题,考虑数据清洗或兼容处理。 紧急发布/回滚: 对于严重影响线上用户的问题,优先考虑紧急发布修复补丁,或者在无法快速修复的情况下,采取回滚到上一个稳定版本的方式。 复盘与预防: ...

June 26, 2025

字节-飞书-校招 · 第 1 轮 · 一面

← 已是第一轮 · 返回本次面经 · 第 1 轮 → 本轮要点: 本次面试主要考察前端基础知识和实际应用能力。 本轮共 20 道题。答案默认折叠,便于先自行作答。 1. 实现一个宽度自适应的搜索框。 题目要点 CSS布局能力: 面试官希望确认候选人对CSS的布局方式(如Flexbox、Grid或传统布局)的掌握程度,以及如何实现元素的响应式和自适应。 响应式设计: 考察候选人是否能考虑不同屏幕尺寸下的用户体验,并运用CSS媒体查询、视口单位等技术实现宽度自适应。 HTML结构: 确认候选人是否能编写语义化且结构清晰的HTML代码。 参考答案 1.1 原理说明 宽度自适应的搜索框是指搜索框的宽度能够根据其父容器的宽度或视口宽度自动调整,以适应不同的屏幕尺寸和设备。实现这种效果通常依赖于CSS的弹性布局(Flexbox)或网格布局(Grid),结合相对单位(如百分比、vw/vh)或弹性单位(如flex属性)。其核心思想是让元素能够"伸缩自如",而不是固定尺寸。 1.2 核心用法 + 示例代码 以下是使用Flexbox实现宽度自适应搜索框的示例: <div class="search-container"> <input type="text" class="search-input" placeholder="请输入搜索内容"> <button class="search-button">搜索</button> </div> .search-container { display: flex; width: 100%; /* 占据父容器的全部宽度 */ max-width: 600px; /* 设置最大宽度,防止过宽 */ margin: 20px auto; /* 居中显示 */ border: 1px solid #ccc; border-radius: 5px; overflow: hidden; /* 防止内容溢出 */ } .search-input { flex-grow: 1; /* 占据剩余空间 */ padding: 10px; border: none; outline: none; /* 移除聚焦时的边框 */ font-size: 16px; } .search-button { padding: 10px 15px; background-color: #007bff; color: white; border: none; cursor: pointer; font-size: 16px; } .search-button:hover { background-color: #0056b3; } /* 媒体查询,适应小屏幕 */ @media (max-width: 768px) { .search-container { max-width: 90%; } } 场景说明: ...

June 26, 2025

字节-本地生活-校招 · 第 1 轮 · 二面

← 第 1 轮 · 返回本次面经 · 已是最后一轮 → 本轮要点: 本轮面试重点考察候选人的项目经验、技术深度和工程化思维。主要包括: 算法编程能力:通过合并有序数组等题目考察基本编程功底 项目经验:深入考察实习期间的技术选型、架构设计等关键决策 微前端技术:重点关注跨应用通信、样式隔离等核心问题 AI 应用实践:考察将新技术应用到工程实践中的能力 跨窗口通信:考察复杂场景下的技术方案设计能力 本轮共 15 道题。答案默认折叠,便于先自行作答。 1. 将两个升序数组合并为一个升序数组 题目要点 数组操作能力 双指针算法应用 原地修改的实现 边界条件处理 参考答案 这道题可以使用双指针从后向前遍历的方法,将较大的数放入nums1的末尾。代码实现如下: function merge(nums1, m, nums2, n) { let p1 = m - 1; // nums1的指针 let p2 = n - 1; // nums2的指针 let p = m + n - 1; // 合并后数组的指针 while (p2 >= 0) { // 只要nums2还有元素需要合并 if (p1 >= 0 && nums1[p1] > nums2[p2]) { nums1[p] = nums1[p1]; p1--; } else { nums1[p] = nums2[p2]; p2--; } p--; } return nums1; } 算法分析: 时间复杂度:O(m+n),只需遍历一次 空间复杂度:O(1),原地修改不需要额外空间 关键点:从后向前遍历避免覆盖nums1中的有效元素 2. 上一段实习在联想主要做的是什么产品?采用了什么技术架构? 题目要点 这是一道主观性问题,面试官主要考察: 项目描述能力:是否能清晰表达项目背景、目标和价值 技术选型能力:是否有合理的技术决策思路 架构设计能力:是否理解系统设计的关键点 业务理解能力:是否深入理解业务需求和痛点 答题建议:建议从项目背景、技术架构、实现亮点和项目成果四个方面展开。重点说明项目的业务价值和技术特点,展现自己在项目中的贡献和成长。 参考答案 “在联想实习期间,我主要负责一个企业级IT资产管理平台的开发工作。这是一个服务于公司内部的中后台系统,日均活跃用户约2000人,管理着超过10万台设备资产。这个平台的核心价值在于提升IT资产管理效率,降低运维成本。 ...

June 24, 2025

字节-本地生活-校招 · 第 1 轮 · 一面

← 已是第一轮 · 返回本次面经 · 第 1 轮 → 本轮要点: 本轮面试侧重考察候选人前端基础知识的系统掌握程度,包括 CSS 盒模型、选择器机制、ES6 语法、异步任务队列、响应式原理与网络协议等,同时会通过算法题考查思维能力与编码规范。 重点关注以下几个方面: CSS布局与样式:考察对盒模型、选择器的深入理解,以及实际应用中的最佳实践 JavaScript核心:重点关注ES6特性、闭包、异步编程等基础概念的掌握程度 框架原理:主要考察Vue3响应式系统的实现原理与优化思路 工程化思维:通过HTTP、缓存、性能优化等问题考察工程实践经验 算法能力:通过字符串处理等典型题目考察基本编程功底 本轮共 17 道题。答案默认折叠,便于先自行作答。 1. 自我介绍 题目要点 这是一道主观性问题,没有标准答案。面试官主要考察: 表达能力:语言组织、逻辑清晰度 职业规划:技术深度、发展方向 项目经验:技术栈匹配度、解决问题能力 个人特质:学习能力、团队协作 参考答案 “您好,我是XXX,有5年前端开发经验。毕业于XXX大学计算机科学专业,目前在一家互联网公司担任高级前端工程师。 我擅长的技术栈是 Vue 和 React 生态,对前端工程化和性能优化有深入研究。最近两年主要负责公司的低代码平台建设,带领团队完成了从0到1的平台搭建。在这个项目中,我们解决了很多技术难题,比如大型JSON-Schema的渲染性能优化、自定义组件的实时预览等。通过这些优化,平台的页面渲染性能提升了60%,现在支持了超过100个业务团队的日常工作。 在技术深度上,我特别关注前端框架底层原理,写过几篇关于Vue3响应式系统的技术文章,并给社区贡献过几个PR。同时我也在公司内部主导了前端性能监控体系的建设,建立了从采集、分析到报警的完整链路。 选择字节跳动是因为被这里浓厚的技术氛围吸引,也认可公司在前端领域的技术实力。我希望能在更大的平台上,和优秀的团队一起解决更有挑战的问题。” 答题建议结构 基本信息与技术栈(15-20秒) 教育背景 工作年限 技术栈概览 核心项目经历(30-40秒) 1-2个最有代表性的项目 突出个人贡献和技术难点 技术深度展示(20-30秒) 专注的技术领域 技术产出或开源贡献 职业规划(10-15秒) 对岗位的理解 个人发展诉求 答题要点提示 时间控制在90秒左右 按照时间重要性安排内容比重 突出个人特色,避免平铺直述 适度准备,保持自然流畅 结合岗位特点,突出匹配度 2. 标准盒模型与IE盒模型的区别,如何通过CSS切换两种模型? 题目要点 考察对CSS盒模型的深入理解,包括两种盒模型的区别、计算方式及其对布局的影响。同时也考察在工程实践中如何合理使用box-sizing,以及不同盒模型在响应式布局中的应用场景和性能影响。 参考答案 1.1 原理说明 两种盒模型的区别: 标准盒模型 (content-box): • width/height 仅包含内容区域 • 实际占用空间 = width + padding + border + margin • 优点:精确控制内容区域大小 • 缺点:需要额外计算实际占用空间 ...

June 24, 2025

react 组件设计模式

首先我们想一个问题,那就是 为什么要学习设计模式? 原因我总结有以下几个方面。 1. 功能复杂,逻辑复用问题。 首先 React 灵活多变性,就决定了 React 项目可以应用多种设计模式。但是这些设计模式的产生也确实办了实事: 场景一: 在一个项目中,全局有一个状态,可以称之为 theme (主题),那么有很多 UI 功能组件需要这个主题,而且这个主题是可以切换的,就像 github 切换暗黑模式一样,那么如何优雅的实现这个功能呢? 这个场景如果我们用 React 的提供者模式,就能轻松搞定了,通过 context 保存全局的主题,然后将 theme 通过 Provider 形式传递下去,需要 theme ,那么消费 context ,就可以了,这样的好处是,只要 theme 改变,消费 context 的组件就会重新更新,达到了切换主题的目的。 场景二: 表单设计场景也需要一定程度上的 React 的设计模式,首先对于表单状态的整体验证需要外层的 Form 绑定事件控制,调度表单的状态下发,验证功能。内层对于每一个表单控件还需要 FormItem 收集数据,让控件变成受控的。 这样的 Form 和 FormItem 方式,就是通过组合模式实现的。 2. 培养设计能力,编程能力 熟练运用 React 的设计模式,可以培养开发者的设计能力,比如 HOC 的设计 ,公共组件的设计 ,自定义 hooks 的设计,一些开源的优秀的库就是通过 React 的灵活性和优秀的设计模式实现的。 例子: 比如在 React 状态管理工具中,无论是 react-redux ,还是 mobx-react,一方面想要把 state 和 dispatch 函数传递给组件,另一方面订阅 state 变化,来促使业务组件更新,那么整个流程中,需要一个或多个 HOC 来搞定。于是 react-redux 提供了 connect,mobx-react 提供了 inject ,observer 等优秀的 hoc。由此可见,学会 React 的设计模式,有助于开发者小到编写公共组件,大到开发开源项目。 ...

December 17, 2024

React函数组件更新

React的函数组件(Function Components)自Hooks推出以来已成为React开发的主流方式。理解函数组件的更新原理对于编写高效、可维护的React应用至关重要。本文将深入探讨React函数组件的更新机制。 一、函数组件与类组件的本质区别 在深入更新原理前,我们需要明确函数组件与类组件的根本区别: 类组件:是类的实例,拥有实例属性和生命周期方法 函数组件:是纯函数,接收props作为参数,返回JSX 这种本质区别决定了它们的更新行为完全不同。 二、函数组件的执行机制 当React需要渲染一个函数组件时,它只是简单地调用这个函数: function MyComponent(props) { return <div>{props.message}</div>; } // React内部大致这样处理 const element = MyComponent({ message: 'Hello' }); 每次渲染都是全新的函数调用,所有局部变量和函数都会重新创建。这与类组件形成鲜明对比,类组件在更新时会复用同一个实例。 三、触发更新的场景 函数组件的更新主要由以下情况触发: 父组件重新渲染:即使props未变化,父组件渲染也会导致子组件重新渲染 props发生变化:当传入组件的props值改变时 状态更新:通过useState、useReducer等Hook更新状态 context变化:组件订阅的context值发生变化 Hooks依赖变化:useEffect、useMemo等Hook的依赖项发生变化 四、React的渲染流程 函数组件的更新遵循React的渲染流程: 触发更新:通过setState、父组件渲染等途径触发更新 协调阶段(Reconciliation): React调用函数组件获取新的JSX 与上一次渲染的JSX进行对比(Virtual DOM Diff) 提交阶段(Commit): 将差异应用到真实DOM 执行useLayoutEffect的回调 浏览器绘制:浏览器重绘屏幕 副作用执行:执行useEffect的回调 五、Hooks与组件更新 Hooks是函数组件能够拥有状态和生命周期的关键。理解Hooks的工作机制对理解组件更新至关重要。 useState的工作原理 const [count, setCount] = useState(0); React会在组件首次渲染时为每个useState调用分配一个"状态单元" 后续更新时,React会按照Hooks的调用顺序来提供对应的状态值 setCount调用会触发组件的重新渲染 useEffect与更新 useEffect(() => { // 副作用代码 return () => { // 清理函数 }; }, [dependencies]); 组件每次渲染后,React会比较依赖项数组 如果依赖项变化或没有提供依赖项数组,副作用会重新执行 清理函数会在副作用重新执行前或组件卸载时执行 六、优化更新性能 由于函数组件每次更新都会完整执行函数体,我们需要一些优化手段: ...

December 17, 2024

react 渲染机制

前言 文本分为两大部分讲解,一部分是首次挂载渲染原理,另一部分是更新和卸载原理,很多地方非常抽象,希望大家仔细阅读,不然容易脱节。废话不多话,开车!! 正文 在开始之前,需要一些前置知识才能帮助我们更好的理解整个渲染过程。首先就是生命周期(16版本之后),为什么要讲一下生命周期?跟渲染原理有关系吗?当然有,如果你不理解渲染原理的话,更新一个嵌套很深的组件你甚至连父与子生命周期执行的先后顺序都不知道。本文直接对照16版本之后的新生命周期进行讲解,就不讲解老版本了。 初探-生命周期 顾名思义,跟人生一样,生命周期就是一个组件从诞生到销毁的过程。React在组件的生命周期中注册了一系列的钩子函数,支持开发者在其中注入代码,并在适当的时机运行。这里指的生命周期仅针对于类组件中的钩子函数。因为生命周期不是本文的重点,所以Hooks中的新增的钩子函数在本文中均不涉及,可以以后出个Hooks原理篇。 从图中可以看到,我把生命周期分为了挂载阶段、更新阶段、卸载阶段三个阶段。同时,在挂载阶段和更新阶段都会运行getDerivedStateFromProps和render,卸载阶段很好理解,只有一个componentWillUnMount,在卸载组件之前做一些事情,通常用来清除定时器等副作用操作。那么挂载阶段和更新阶段中的生命周期我们来逐一看下每个运行点及作用。 1. constructor 在同一个类组件对象只会运行一次。所以经常来做一些初始化的操作。同一个组件对象被多次创建,它们的construcotr互不干扰。 注意:在construcotr中要尽量避免(最好禁止)使用setState。 我们都知道使用setState会造成页面的重新渲染,但是在初始化阶段,页面都还没有将真实DOM挂载到页面上,那么重新渲染的又有什么意义呢。除异步的情况,比如setInterval中使用setState是没问题的,因为在执行的时候页面早已渲染完成。但也最好不要,容易一些引起奇怪的问题。 constructor(props) { super(props); this.state = { num: 1 }; //不可以,直接Warning this.setState({ num: this.state.num + 1 }); //可以使用,但不建议 setInterval(()=>{ this.setState({ num: this.state.num + 1 }); }, 1000); } 2. 静态属性 static getDerivedStateFromProps 该方法是一个静态属性,在16版本之前不存在,在新版生命周期中主要用来取代componentWillMount和componentWillReceiveProps,因为这两个老生命周期方法在一些开发者不规范的使用下极容易产生一些反模式的bug。因为是静态方法,所以你在其中根本拿不到this,更不可能调用setState。 该方法在挂载阶段和更新阶段都会运行。它有两个参数props和state当前的属性值和状态。它的返回值会合并掉当前的状态(state)。 如果返回了非Object的值,那么它啥都不会做,如果返回的是Object,那么它将会跟当前的状态合并,可以理解为Object.assign。通常情况下,几乎不怎么使用该方法。 /** * 静态方法,首次挂载和更新渲染都会运行该方法 * @param {*} props 当前属性 * @param {*} state 当前状态 */ static getDerivedStateFromProps(props, state){ // return 1; //没用 return { num: 999, //合并到当前state对象 }; } 3. render 最重要的生命周期,没有之一。用来生成虚拟节点(vDom)树。该方法只要遇到需要重新渲染都会运行。同样的,在render中也严禁使用setState,因为会导致无限递归重新渲染导致爆栈。 ...

December 17, 2024