React面试题

解释一下React中的Refs及其用途,并给出使用Refs的两种方式。

Refs是React中用于访问DOM元素或在函数组件中创建实例引用的一种方式。它们主要用于管理焦点、文本选择、
触发强制渲染或与第三方DOM库集成。有两种主要的创建Refs方式:
    使用React.createRef():在类组件中,可以在构造函数中创建一个ref,然后通过current属性访问DOM元素。
    使用回调Refs:同样适用于类组件和函数组件,通过传递一个回调函数给ref属性,该函数会在组件挂载或更新时
    被调用,传入当前的DOM元素或React实例作为参数。
    使用React Hooks中的useRef:在函数组件中,可以使用useRef Hook来创建一个可变的ref对象。

React 类组件和函数组件之间的区别是什么?。

定义方式
    函数组件是纯函数,它接收 props 作为输入并返回一个React元素,描述了应该在屏幕上渲染什么
    类组件是ES6 类组件就是基于ES6语法,通过继承 React.component 得到的组件。
状态与生命周期
    函数组件: React hooks为函数组件提供了状态,也支持在函数组件中进行数据获取、订阅事件解绑事件等等。
    类组件:类组件可以定义自己的状态(this.state)并通过 setState 方法更新状态,触发组件重新渲染。
    同时,类组件支持复杂的生命周期方法,如 componentDidMount, shouldComponentUpdate,
    getDerivedStateFromProps 等,用于处理挂载、更新、卸载等不同阶段的逻辑。
性能:
    函数组件 每次渲染组件中的变量和事件处理函数就会重新被创建。每次渲染React都会提供给这次渲染的
    state快照,也就是说state 的值始终“固定”在一次渲染的各个事件处理函数内部。特别是 React.memo可以
    用来优化纯函数组件,避免不必要的渲染。
    类组件:类组件捕获最新的值(永远保持一致)当实例的state或props属性发生修改时,类组件直接使用
    this(组件的实例),所以可以直接获取组件最新的值。类组件由于其生命周期的存在,有时可能导致
    不必要的复杂性和性能开销。

函数组件相比较类组件,优点是更轻量与灵活,便于逻辑的拆分复用。
类组件可以获取实例化的 this,并且基于 this 做各种操作,函数组件不行

请列举React和vue的相似性和差异性 ?

相似性
    组件化开发:两者都采用了组件化的开发模式,允许开发者将UI拆分成独立、可复用的组件,
    这极大地提高了代码的可维护性和开发效率。

    虚拟DOM:React和Vue都利用虚拟DOM来提高页面渲染性能,通过计算虚拟DOM的差异来最小化实际DOM的操作。
    声明式编程:它们都推崇声明式编程风格,开发者只需描述UI应该呈现出什么样子,而框架负责处理底层的DOM操作和状态更新逻辑。

    单向数据流与响应式数据绑定:虽然Vue更强调双向绑定,但两者都能实现数据变化驱动视图更新的机制,使数据管理更加直观和高效。

    庞大的生态系统:React和Vue都有丰富的生态系统,包括路由管理、状态管理、UI库、构建工具等,支持开发者快速搭建复杂应用。
差异性
    模板语法与JSX:Vue使用基于HTML的模板语法,直接在模板中嵌入指令和表达式;而React采用JSX,允许在
    JavaScript中编写类似HTML的代码,使得JavaScript完全控制了渲染过程。

    状态管理:虽然两者都可以集成第三方状态管理库(如Redux、Vuex),Vue通过官方提供的Vuex更强调状态
    管理的中心化;React中状态管理的选择更为灵活,Redux是最著名的,但非唯一选择。

    学习曲线:Vue通常被认为学习曲线更平缓,文档友好,对于初学者来说更容易上手;React由于其更加底层
    和灵活,初学者可能需要更长时间来掌握。

    体积与性能:Vue的核心库相对较小,初始渲染速度快;而React在某些场景下,尤其是在大型应用中,
    通过优化可以达到极高的性能。

    框架与库:Vue是一个完整的框架,提供了从路由到状态管理等一系列解决方案;React则更倾向于一个库,
    专注于视图层,开发者需要自行选择搭配其他库来构成完整的开发栈。

    更新机制:Vue采用的是自动追踪依赖的观察者模式,数据变化会自动触发视图更新;React依赖开发者手动
    管理状态,通过setState触发重渲染。

React Hook 的使用限制有哪些?

只能在函数组件或自定义Hook中使用:Hooks不能在类组件中使用。如果你想在现有的类组件中使用Hook,
你可能需要先将其转换为函数组件。

Hooks的调用顺序必须一致:在组件的每次渲染过程中,调用Hook的顺序必须保持一致。这是因为React依赖这个
顺序来正确地重建状态。违反这一规则会导致难以预料的行为。

不能在循环、条件或嵌套函数中调用Hook:Hooks必须在React函数组件的顶层调用,不能放在循环、条件分支或
嵌套的函数调用中。这是为了确保每次渲染时Hook的调用顺序保持不变,并且使得代码易于理解和调试。

自定义Hook必须以use前缀命名:虽然这不是一个强制性的限制,但按照约定,自定义Hook的命名应该以use开头。
这样做可以帮助开发者识别哪些函数是Hooks,并保持代码的一致性。

不能在常规的JavaScript函数中调用Hooks:Hooks只能在React函数组件或自定义Hook中调用。这意味着你不
能在事件处理器、setTimeout回调或其他普通的JavaScript函数中直接使用Hooks
。
Hooks不能在异步函数中直接使用:虽然可以在async函数组件中使用Hooks,但需要注意的是,不能直接在async函数
内部调用useState或useEffect等Hooks。这是因为异步函数的执行体不是同步的,可能导致React无法正确追踪Hook
的调用顺序。

React Hooks在平时开发中需要注意的问题和原因?

遵守Hooks规则
    只在最外层使用Hooks:不要在循环、条件或嵌套函数中调用Hook。这是因为Hooks依赖于调用顺序,
    保持一致的调用顺序对于React维护内部状态至关重要。
    不要在常规函数中调用Hooks:Hooks只能在React函数组件或自定义Hooks中使用。不能在普通的JavaScript
    函数中调用Hooks,因为它们依赖于React组件的生命周期。
    为了防止闭包捕获到旧值,就要确保在提供给hook的回调中使用的prop或者state都被指定为依赖性。
使用Effect Hook时注意副作用
    清理副作用:在使用useEffect时,如果Effect中包含了可能需要清理的资源(如定时器、订阅等),应该
    返回一个清理函数。这能确保在组件卸载或下次Effect执行前,资源得到妥善处理。
    依赖数组:useEffect的第二个参数(依赖数组)非常重要,它告诉React何时重新执行Effect。遗漏依赖
    可能导致不正确的行为,而添加过多的依赖可能会导致不必要的渲染。
理解Hooks的执行时机
    Hooks在每次渲染时执行:记住,每次组件渲染时,React都会按顺序执行所有的Hooks。这意味着不应该在
    Hooks内部进行条件判断来控制副作用的执行,而应该通过依赖数组来控制。
自定义Hooks的设计
    重用逻辑:自定义Hooks是封装和复用逻辑的强大工具。确保它们的名字以use开头,遵循最佳实践,使其易
    于理解和测试。
    避免副作用:虽然自定义Hooks可以执行副作用(如API调用),但最好将它们设计为纯粹的逻辑复用工具,
    将副作用留给使用它们的组件或专门的Effect Hooks处理。
性能考量
    避免不必要的渲染:使用React.memo对函数组件进行性能优化,避免不必要的重新渲染。同时,注意
    useCallback和useMemo的使用,以缓存计算结果或回调函数,减少子组件不必要的更新。

简述什么是React 高阶组件?

React高阶组件(Higher-Order Components,简称HOC)是React中用于复用组件逻辑的一种高级技术。它是一种函
数,接受一个组件作为输入,返回一个新的增强过的组件作为输出。这种模式允许你在一个组件外部添加共享的功能,
如数据操作、权限控制、主题设置等,而无需修改组件本身的代码。
使用场景包括:
    状态管理:为无状态组件注入状态管理逻辑。
    权限控制:在渲染组件之前检查用户权限。
    数据封装:在组件外部处理API请求,将数据作为props传递给组件。
    复用UI逻辑:如为多个组件添加相同的样式调整、事件处理等。
    性能优化:比如实现shouldComponentUpdate来避免不必要的渲染。

高阶组件并不是React API的一部分,它是基于React的组合特性而形成的设计模式。为了代码的复用性,减少代码的冗余。

请简述useCallback 和 useMemo 的使用场景 ?

useMemo: 
    当组件中有复杂计算或者创建大对象的情况,而且这些计算或对象的依赖不会频繁变化时,可以使用useMemo来缓
    存计算结果或对象,避免每次渲染时都重新计算。适用于计算值,尤其是那些计算成本较高的情况,
    比如处理大数据过滤、排序等操作。
    适合用于 memoization,确保在依赖项不变的情况下,返回的值也是不变的,从而减少子组件不必要的重新渲染
useCallback: 
    主要用于优化函数作为props传递给子组件时的性能问题。当父组件渲染导致子组件不必要的重新渲染,
    而子组件的重新渲染仅仅是因为接收到的函数props引用发生了变化(即使函数内部逻辑并未改变)时,
    可以使用useCallback来缓存该函数。
    你需要传递给子组件的回调函数依赖于某些值,且这些值变化时才需要重新生成回调函数时。
    适合于函数类型的值,确保在依赖项不变的情况下,返回的函数引用也是不变的

完整的简述React 的 diff 过程 ?

树对比: React采用深度优先、同层比较的策略遍历新旧虚拟DOM树。把树形结构按照层级分解,只比较同级元素。
节点类型比较:
    如果新旧节点的类型不同(例如,一个是<div>,另一个是<span>),React会直接替换整个节点及其子树。
    如果类型相同,则继续比较属性(props)和子元素。
属性(Props)比较:
    对于同一类型的节点,React会比较新旧节点的属性是否有差异,如有差异则更新相应的DOM属性。
子节点比较:
    对于列表,React使用“key”属性来高效地识别哪些子元素被移动、添加或删除,而不是简单地重新渲染整个列表。
    没有指定key或者key选择不当会降低这一过程的效率。
    对于文本节点和单一子节点,直接比较它们的内容变化并更新。
递归比较:
    一旦发现差异,React会递归地在子树中继续执行上述比较过程,直到找到所有需要更新的部分。
并行与分块更新:
    一些情况下,React可能会将大的更新任务分割成小块,以避免阻塞用户界面过长时间,特别是在Web Workers
    可用的环境中。
React Fiber: 引入的Fiber架构,改进了diff和渲染流程,使其能够中断和恢复工作,实现更细粒度的控制和
更好的性能,特别是在处理大量或复杂更新时。

请简述react-router 和 react-router-dom 的有什么区别?

react-router
    核心库:react-router 是React Router的核心库,包含了路由(Routing)的基本功能和逻辑,如路由匹配、
    导航等功能。它是一个平台无关的库,意味着它不包含任何特定于浏览器的API。
    适用场景:如果你正在开发一个非Web端的应用,比如使用React Native开发移动应用,你可能只需要
    react-router的核心功能,因为它不包含任何DOM相关的API。
    API:提供了如BrowserRouter, Route, Switch, Link, NavLink, Redirect, Router, generatePath等
    基本路由组件和函数,但不包括基于DOM的API,如withRouter。
react-router-dom
    专为Web设计:react-router-dom是基于react-router构建的,专门用于Web浏览器环境。它在react-router
    的基础上,添加了一些针对浏览器环境的额外功能和组件。
    附加功能:除了包含react-router的所有功能外,react-router-dom还额外提供了如<BrowserRouter>, 
    <Link>, <NavLink>等针对Web开发的组件,以及<Prompt>, <HashRouter>, <MemoryRouter>等特定于
    浏览器环境的路由处理工具。
    适用场景:如果你正在开发一个Web应用,那么react-router-dom会是更直接的选择,因为它提供了所有必要
    的DOM相关的API和组件,可以直接用于创建和管理Web应用中的路由。

总结:react-router是路由的基础库,提供了路由的核心功能,适用于任何React应用。而react-router-dom是
建立在react-router之上的,专门针对Web浏览器环境进行了扩展,提供了更方便的DOM操作API和组件,
是Web开发中最常用的React路由库

React中如何避免不必要的render?

使用React.memo: 对于函数组件,可以使用React.memo包裹组件。这会让React在组件 props 发生变化时先进行
浅比较,只有当props有改变时才会重新渲染组件。这对于纯展示型组件(即组件的输出只依赖于props,
不依赖于状态或上下文)特别有效。

使用引用类型避免不必要的props传递: 当一个大型对象或数组作为prop传递给子组件,即使对象内容未变但
引用地址改变也会导致子组件重新渲染。可以考虑使用React.useMemo或useCallback来缓存这些值,
避免无意义的更新。

避免在父组件的render函数中创建新的对象或数组: 每次render时创建新的引用会导致子组件即使props内容
相同也会重新渲染。确保使用的对象或数组引用保持不变,除非其内容确实发生变化。

Context API中的useContext: 当使用React的Context API时,可以通过在消费者组件中使用React.memo结合
useContext来避免不必要的渲染。

useEffect()的清除机制是什么?在什么时候执行?

useEffect的清除机制是通过其返回的一个函数来实现的。

组件卸载(unmount)之前:当组件从DOM中移除时,React会先调用这个返回的清理函数,执行必要的清理工作,
比如取消网络请求、清理定时器、移除事件监听器等,以避免造成内存泄漏或不必要的副作用。

依赖项改变,执行下一次effect之前:如果useEffect的依赖数组(dependency array)非空,并且其中的值
发生了变化,React会在执行新的effect回调之前先调用上一次effect的清理函数。这意味着每次依赖项改变导致的
effect重新执行前后,都会有一个清理过程,确保副作用的干净切换。

React shouldComponentUpdate有什么用?为什么它很重要?

shouldComponentUpdate:判断组件是否应该更新。

组件状态数据或者属性数据发生更新的时候,组件会进入存在期,视图会渲染更新。在生命周期方法 
should ComponentUpdate中,允许选择退出某些组件(和它们的子组件)的和解过程。

和解的最终目标是根据新的状态,以最有效的方式更新用户界面。如果我们知道用户界面的某一部分不会改变,
那么没有理由让 React弄清楚它是否应该更新渲染。通过在 shouldComponentUpdate方法中返回 false, 
React将让当前组件及其所有子组件保持与当前组件状态相同。

在React中如何防范XSS攻击?

XSS(Cross-Site Scripting,跨站脚本攻击)是一种常见的网络安全风险,攻击者通过注入恶意脚本到网页中,
使之在用户的浏览器上执行,从而窃取用户数据、操纵网页内容或进行其他恶意活动。

使用React的危险ouslySetInnerHTML谨慎处理HTML字符串:
    默认情况下,React会转义插入的所有内容,防止XSS攻击。但如果你需要渲染富文本或用户输入的HTML,
    可以使用dangerouslySetInnerHTML属性。但使用时必须非常小心,确保内容是经过验证和清理的。
转义用户输入:
    对于需要展示但非HTML渲染的用户输入,确保所有输出到DOM的文本都被恰当转义,避免执行JavaScript代码。
    可以使用像escape或第三方库如he来转义特殊字符。
使用安全的库处理富文本:
    利用成熟的富文本编辑和渲染库(如Draft.js、Quill等),它们通常内置了XSS防护机制。
HttpOnly Cookie
    对于包含敏感信息的Cookie,设置HttpOnly属性,使其不能通过JavaScript被访问,这样即使存在XSS漏洞,
    攻击者也无法直接盗取这类Cookie。
Content Security Policy (CSP)
    设置响应头中的Content-Security-Policy,限制页面只能加载指定来源的脚本、样式和图片,有效防止外部
    注入的恶意内容被执行。

React 并发模式是如何执行的?

React 并发模式:它旨在通过分片更新(time-slicing)、优先级调度和暂停/恢复渲染等机制来提升用户体验和
应用性能。
分片更新(Time-Slicing):
    在并发模式下,React能够将复杂的UI更新任务分割成小块,这些小块被称为“工作单元”。浏览器在空闲时间
    (例如当脚本执行完毕,等待下一帧渲染之前)会逐个执行这些工作单元。这样可以避免长时间阻塞主线程,
    使得应用在处理耗时任务时仍能保持响应。
优先级调度(Priority Scheduling):
    React根据UI更新的重要性给予不同的优先级。例如,用户交互(如点击)触发的更新可能被赋予更高的优先级,
    而背景数据加载引起的更新则可能被赋予较低的优先级。这样,紧急的UI更新可以更快地完成,提高用户体验。
Suspense API:
    Suspense组件允许你“暂停”一个组件的渲染,直到其所需的数据或资源准备就绪。这意味着React可以先渲染其它
    部分的UI,而不是阻塞整个渲染过程等待某个慢速资源加载完成。这对于实现如懒加载、数据预取等策略非常有
    用。
可中断和恢复的渲染:
    在执行渲染任务的过程中,React可以随时根据需要中断当前任务(比如为了响应更高优先级的更新或避免阻塞UI
    响应),并在适当的时候恢复执行。这使得React能够更加灵活地管理渲染流程,确保重要的更新得到及时处理。
使用useTransition和useDeferredValue等Hooks:
    这些Hooks帮助开发者控制UI更新的时机和方式。例如,useTransition可以让一系列的状态更新合并并以动画
    的形式展示,而useDeferredValue则可以延迟非关键状态的更新,减少不必要的渲染。

React ⾼阶组件、Render props、hooks 有什么区别,为什么要 不断迭代 ?

高阶组件特点:
    复用逻辑:通过封装通用功能,如数据获取、权限校验等。
    不改变组件结构:HOC在不修改原组件代码的前提下,增强其功能。
    侵入性:使用HOC会改变组件的结构,使得调试和阅读代码可能变得复杂
Render Props特点:
    灵活性:通过传递一个函数作为prop,决定父组件如何渲染。
    非侵入性:相比HOC,render props不改变组件层次结构,更易于理解和调试。
    易于分享状态逻辑:可以将共享状态或逻辑封装在一个组件中,并通过render prop暴露出去。
hooks特点:
    函数组件的增强:直接在函数组件内部使用state、生命周期等特性。
    易于理解和测试:代码更加扁平化,易于阅读和测试。
    组合逻辑:使用useEffect、useMemo、useCallback等,可以灵活地组合和复用逻辑。
总结:
    提升开发体验:每一代技术的迭代都旨在简化代码、提高可读性和可维护性,降低学习曲线。
    性能优化:随着框架的成熟,新特性往往带来性能上的改进。
    响应开发者需求:React社区的发展推动了技术的革新,新的模式往往是为了解决开发者在实际项目中
    遇到的问题。
    拥抱函数组件趋势:Hooks的引入反映了函数组件逐渐成为主流的趋势,它使得函数组件能够拥有类组件的特性,
    同时保持代码的简洁性。

哪些方法会触发 React 重新渲染?重新渲染 render 会做些什么 ?

重新渲染的方法:
    setState方法:这是最直接也是最常见的触发重新渲染的方式。当组件内部调用this.setState()方法
    更新状态时,React会标记该组件及其子组件需要重新渲染。

    props的变化:当一个组件接收到新的props时,如果这些新props与之前的props不严格相等(浅比较),
    React会重新渲染这个组件。

    Context值的变化:如果组件订阅了Context,并且Context的值发生了变化,那么这个组件也会重新渲染。

    使用React.memo的组件接收到新props:对于使用React.memo包装的函数组件,只有当props发生改变时才会
    触发重渲染,且这种改变需通过深比较判断。

    useState或useReducer Hook中的状态更新:在函数组件中,通过useState或useReducer Hook管理的状态
    发生变化时,也会导致组件重新渲染。

    使用useEffect Hook的依赖项变化:当依赖项数组中的值发生变化时,对应的useEffect回调会在渲染完成后
    执行,并可能因此引起组件的重新渲染。

渲染时执行:
    调用render方法:React会再次调用组件的render方法(对于函数组件就是执行函数体)。在这个方法中,
    React会根据最新的props和state计算出一个新的虚拟DOM树(React元素)。

    对比虚拟DOM:React接着会将新计算出的虚拟DOM与上一次渲染的虚拟DOM进行对比(也称为Diffing过程),
    找出两者的差异。

    最小化DOM操作:基于差异,React仅对实际DOM进行必要的最小化修改,以高效地更新用户界面,而不是每次
    都重建整个DOM树。

    生命周期方法/Effect Hooks:在渲染过程中和之后,可能会执行特定的生命周期方法(对于类组件)或
    Effect Hooks(对于函数组件),比如componentDidUpdate或useEffect,用于执行副作用操作,
    如数据获取、DOM操作等。

简述Redux 和 Vuex 有什么区别,它们的共同思想 ?

Redux特点:
    纯函数:Redux 强调 reducer 必须是纯函数,即给定相同输入始终产生相同输出,这有利于预测状态变化和调试。
    单一数据源:Redux 应用只有一个全局的 store,其中包含整个应用的状态树。所有状态更新必须通过 
    dispatch 动作来触发。
    动作与中间件:Redux 中,状态更新通过 actions 表达意图,而中间件机制允许在 actions 分发到 
    reducers 之前进行拦截和处理,增强了灵活性。
    不直接修改状态:状态是只读的,必须通过 dispatch action 来触发 state 更新。
    Redux 在检测数据变化的时候,是通过 diff 的方式比较差异的,
Vuex特点:
    专为Vue设计:Vuex 是 Vue.js 官方的状态管理模式,与Vue的组件系统深度集成,使用起来更加自然。
    状态管理模式:虽然也采用了单向数据流的概念,但Vuex在命名和结构上更加贴近Vue开发者习惯,如 
    state、mutations、actions 和 getters。
    模块化:Vuex 支持模块划分,有助于大型应用的状态管理,使得状态树更加清晰、易于维护。
    Mutation 必须同步:Vuex 中的 mutation 用于更改状态,并且必须是同步的,这保证了状态更新的可追踪性。
    Actions 可以包含异步操作。
    Vuex其实和Vue的原理一样,是通过 getter/setter来比较的
共同点:
    集中式状态管理:两者都将应用的状态集中存储在单一的store中,解决了跨组件共享状态的问题,提高了
    状态的可维护性和可预测性。
    单向数据流:状态更新遵循严格的单向数据流原则,即从action出发,经由reducer/mutation更新state,
    最终影响到UI,这有助于追踪数据流动,减少bug。
    可预测的状态:通过明确的动作(actions)和纯函数(reducers/mutations)来处理状态变化,确保了
    状态变更的可预测性。

简述React 与 Vue 的 diff 算法有何不同 ?

React的Diff算法:
    同层比较:React的diff算法主要发生在同一层级的节点之间,它假设同一个父节点下的子节点顺序
    不会发生大的变动,因此只会对同层级的子节点进行比较。
    递归对比:React的diff是深度优先、自顶向下的。将单一节点比对转化为了 3 种类型的比对,分别是树、
    组件及元素,以此提升效率,React会直接替换该部分的子树,而不会进一步比较子节点。
    批量更新:React 16引入了Fiber架构,它改变了React执行更新的方式,允许React以更细粒度控制渲染过程,
    包括暂停、恢复和优先级排序,从而优化了更新性能。
Vue的Diff算法:
    异步队列更新:Vue默认采用异步更新策略,数据变化并不会立即触发DOM更新,而是将这些变化收集起来,
    在下一次事件循环的微任务队列中批量执行。这种方式可以减少不必要的渲染,提高性能。
    组件树的patch过程:Vue在diff过程中,会对新旧虚拟DOM树进行深度优先遍历,并且通过记录每个节点的
    “标记”来确定如何更新DOM。Vue的diff算法也倾向于复用已有节点,减少DOM操作。
    优化策略:Vue有更细粒度的优化策略,如对于静态内容的标记和跳过,以及对v-if和v-for的特殊处理,
    确保在这些常见场景下能有更高的更新效率。
总结:React更侧重于通过分治策略和keyed diff来优化比较过程,而Vue则通过异步更新策略和动态指令系统
来提升性能和灵活性。两者都是现代前端框架中高效更新机制的重要组成部分。

简述React 中的高阶组件运用了什么设计模式 ?

React 中的高阶组件(Higher-Order Components, HOC)运用了装饰器设计模式(Decorator Pattern)。
装饰器模式是一种结构型设计模式,它允许在不修改原始类代码的情况下,动态地给一个对象添加额外的功能或责任。

在React中,高阶组件是一个函数,它接收一个组件作为参数,并返回一个新的组件。这个新组件通常会基于传入
组件进行功能的增强,比如添加日志记录、数据获取、权限校验等功能,而无需修改原始组件的代码。这一过程类似
于装饰器模式中为对象添加附加职责的方式,通过包装原始对象来扩展功能,保持了原始组件的纯净性和可重用性。

高阶组件的这种设计不仅促进了代码的复用,还提高了组件的可维护性和灵活性,使得功能的添加和移除变得更加容
易,同时也遵循了开放封闭原则——对扩展开放,对修改封闭。

简述React Hooks 解决了哪些问题 ?

组件间逻辑复用难题:在Hooks之前,要复用状态逻辑或生命周期方法,通常需要提取为高阶组件(HOC)或
Render Props模式,但这两种方式都会增加组件的嵌套复杂度,且不够直观。Hooks允许直接在函数组件中使用
状态和副作用逻辑,通过简单的函数调用来复用这些逻辑,极大提高了代码的可读性和可维护性。

类组件的复杂性:类组件结合了JavaScript类的特性,如this指向问题、生命周期方法等,这些对新手来说有一定
的学习门槛。Hooks完全基于函数组件,消除了this绑定的困扰,使得组件更简洁、易于理解和测试。

状态管理的困惑:虽然Redux等状态管理库可以解决跨组件状态共享的问题,但它们引入了额外的学习曲线和配置。
useState、useReducer、useContext等Hooks为组件内状态管理提供了更轻量级的解决方案,使得小型项目或组件
内部状态管理更加直接和高效。

生命周期方法的混乱:React类组件中有多个生命周期方法,开发者经常困惑于何时使用哪个生命周期。Hooks通过
更直观的函数(如useEffect)替代了复杂的生命周期,使得副作用的管理更加清晰和灵活。

测试的便捷性:由于Hooks基于纯函数,没有类和this的复杂性,使得组件和Hook函数更易于单元测试。此外,
Jest等测试框架对Hooks的支持也非常好,提高了测试的效率和覆盖率。

更好的代码组织和可读性:Hooks鼓励将相关的逻辑放在一起,比如将状态和影响该状态的副作用放在同一个地方管理,
这有助于代码的模块化和逻辑的清晰表达。

谈谈你对“Server-Side Rendering (SSR)”和“Client-Side Rendering (CSR)”的理解,以及它们在React中的应用。

SSR是指在服务器端完成React组件的渲染工作,将完全渲染好的HTML页面发送到客户端(浏览器)。
应用:
    SEO友好:搜索引擎爬虫可以直接抓取到完整的HTML内容,有利于搜索引擎优化。
    首屏加载快:用户首次访问时能看到即时内容,提高了用户体验。
    更好的初始用户体验:尤其在低性能设备或网络状况不佳时,用户无需等待JavaScript加载和执行就能看到页面内容。
    实现复杂:需要服务器端渲染的支持,增加了部署和维护的复杂度。
    动态数据处理:服务器需要处理数据获取逻辑,增加了服务器负载。

CSR则是将React组件的渲染过程放在客户端(浏览器)进行。首次请求时,服务器通常只返回一个基本的HTML结构
和JavaScript bundle,之后React在浏览器中执行,构建DOM并处理用户交互。
应用:
    快速开发:开发和部署相对简单,因为所有渲染逻辑都在客户端执行。
    交互体验好:一旦初始页面加载完成,后续的页面交互和更新非常迅速,无需与服务器频繁交互。
    负担转移到客户端:减少了服务器的压力,但对客户端性能有一定要求。
    SEO挑战:传统搜索引擎爬虫难以抓取动态生成的内容,影响SEO排名,但随着Google等搜索引擎对JavaScript
    渲染的支持增强,这一问题有所缓解。
    首屏加载慢:用户首次访问时需要等待JavaScript下载和执行,可能导致白屏时间较长。
powered by GitbookEdit Time: 2024-07-09 16:59:46