欢迎光临
我们一直在努力

React系列-2

说说对受控组件和非受控组件的理解?应用场景?

受控组件是指表单元素的值由 React 的 state 控制,通过 value 和 onChange 实现数据同步,React 作为唯一数据源。
非受控组件则是由 DOM 自身维护表单数据,通常使用 defaultValue 初始化,通过 ref 在需要时获取值。
两者的主要区别是数据控制权不同:受控组件由 React 管理,数据流可预测;非受控组件由 DOM 管理,实现更简单。
实际开发中,复杂表单、实时校验或需要状态联动时一般使用受控组件;而简单提交、文件上传或性能敏感场景可以使用非受控组件。React 官方整体更推荐受控组件。

说说对高阶组件的理解?应用场景?

高阶组件(HOC,Higher-Order Component)本质是一个函数,它接收一个组件作为参数,并返回一个增强后的新组件,用来复用组件之间的通用逻辑。
它本身不是组件,而是一种组件逻辑复用模式,本质类似装饰者模式。
高阶组件通常通过包裹原组件,对 props、生命周期或渲染过程进行增强,比如权限控制、日志埋点、数据获取等。
使用时需要注意透传 props、不修改原组件,以及 ref 需要通过 forwardRef 进行转发。ref 不属于 props,不会自动透传,高阶组件会阻断 ref 的指向,所以需要使用 forwardRef 将 ref 转发到被包装组件,保证外部仍能访问真实组件实例或 DOM。

说说对React Hooks的理解?解决了什么问题?

React Hooks 是 React 16.8 引入的一套函数式 API,它让函数组件可以拥有 state、生命周期以及逻辑复用能力。
Hooks 的核心目标是解决类组件中状态逻辑难复用、生命周期逻辑分散以及 this 使用复杂的问题。
通过 Hooks,我们可以在函数组件中使用如 useState 管理状态、useEffect 处理副作用,并通过自定义 Hook 实现逻辑复用,使组件更加简洁和可维护。
当前 React 官方推荐优先使用函数组件 + Hooks 作为主流开发方式。

Hooks让我们的函数组件拥有了类组件的特性,例如组件内的状态、生命周期。Hook主要解决了三个核心问题:

  • 解决状态逻辑难复用,直接复用逻辑。
  • 解决生命周期逻辑分散问题,useEffect相关逻辑放在一起。
  • 解决 class 的复杂性
  • 常见的Hook

  • useState — 状态管理
  • useEffect — 副作用处理
  • useRef —— 保存 DOM / 可变值
  • useMemo —— 缓存计算
  • useCallback —— 缓存函数
  • useEffect 可以把原来分散在不同生命周期中的“同一类副作用逻辑”集中管理,而不是简单替代所有生命周期。

    为什么 useEffect 不能 async?
    因为 useEffect 需要返回 cleanup 函数,而 async 函数返回 Promise,React 无法将其作为清理函数处理,因此应该在 effect 内部定义 async 函数。
    为什么依赖漏写会 bug?
    因为 useEffect 会形成闭包,如果依赖未声明,effect 不会重新执行,从而捕获旧 state,导致读取到过期数据。

    说说react中引入css的方式有哪几种?区别?

    React 中常见的 CSS 引入方式有四种:内联样式、普通 CSS、CSS Modules 和 CSS-in-JS。
    内联样式适合动态样式但功能有限;普通 CSS 是全局作用域,容易产生样式污染;CSS Modules 通过生成唯一类名实现局部作用域,是目前 React 项目中最常用方案;CSS-in-JS 将样式写在 JS 中,适合组件化和主题化场景。实际开发中通常结合多种方式使用。

    为什么 React 不像 Vue 有 scoped?Vue 有 scoped 是因为它是带编译能力的框架,可以在构建阶段给 DOM 添加唯一属性实现样式隔离;而 React 本身只是 UI 库,不处理 CSS 和构建流程。

    CSS Modules 原理是什么?通过构建工具把类名转换成唯一 hash 值,避免样式冲突。

    在react中组件间过渡动画如何实现?

    React 中组件过渡动画通常通过 react-transition-group 实现,它通过在组件进入和离开阶段自动添加 enter、exit 等 className,使 CSS transition 能够执行动画。CSSTransition 用于单组件动画,SwitchTransition 用于组件切换动画,TransitionGroup 用于列表动画,本质是延迟 DOM 的删除时机以完成动画效果。

    说说你对Redux的理解?其工作原理?

    Redux 是一个可预测的状态管理库,通过 Store 集中管理应用状态。

    单一数据源,整个应用只有一个store,state是只读的,使用纯函数修改状态,createStore创建仓库。getState获取状态。dispatch唯一修改方式。subscribe监听变化。

    组件通过 dispatch action 描述状态变化,Store 将 action 交给 reducer 这个纯函数计算新的 state,并通知订阅组件更新 UI。Redux 通过单向数据流和不可变数据,使状态变化可追踪、可调试,解决了大型 React 应用中状态共享和维护困难的问题。

    说说对Redux中间件的理解?常用的中间件有哪些?实现原理?

    Redux 中间件本质是对 dispatch 的函数增强,它通过函数组合的方式,在 action 到 reducer 之间建立拦截层,从而实现异步处理、日志记录、错误捕获等副作用逻辑。中间件采用三层函数结构 store => next => action,形成类似洋葱模型的调用链,最终生成一个增强版 dispatch。

    redux-thunk(最常用)作用:支持 dispatch 异步函数。
    redux-logger作用:打印 action 和 state 变化。

    中间件本质是一个三层函数:store => next => action,多个中间件通过 applyMiddleware 进行函数组合,形成类似洋葱模型的调用链,最终包装原始 dispatch。

    你在React项目中是如何使用Redux的? 项目结构是如何划分的?

    在 React 项目中,我一般使用 Redux Toolkit 结合 react-redux hooks 来管理全局状态。
    在应用顶层通过 Provider 注入 store,在组件内部通过 useSelector 读取状态,通过 useDispatch 派发 action。
    Redux 主要用于管理跨页面共享数据,比如用户信息、权限数据、购物车等,而局部 UI 状态一般使用 useState 管理。
    在项目结构上,我更倾向于按功能模块划分,而不是传统的 MVC 角色划分。每个功能模块包含自己的 slice、相关 API 和业务逻辑,这样代码内聚性更强,也更方便维护。

    说说React Router有几种模式?实现原理?

    React Router 主要有两种路由模式:Hash 模式和 History 模式。
    Hash 模式通过 URL 中的 # 实现,利用浏览器的 hashchange 事件监听 URL 变化,由于 hash 改变不会向服务器发送请求,因此不会刷新页面。
    History 模式基于 HTML5 的 History API,通过 pushState 和 replaceState 修改浏览器地址栏,同样可以在不刷新页面的情况下改变 URL,并通过 popstate 事件监听历史记录变化。
    两种模式的核心原理都是监听 URL 变化,然后根据路径匹配对应组件并重新渲染,从而实现单页应用的页面切换。

    说说React render方法的原理?在什么时候会被触发?

    React 中 render 的本质是根据 state 和 props 生成新的 Virtual DOM。JSX 会被编译为 React.createElement,从而形成虚拟 DOM 树。React 会将新旧虚拟 DOM 进行 diff 比较,只更新发生变化的部分真实 DOM。
    render 会在 state 更新、props 变化、父组件重新渲染或 forceUpdate 时触发。函数组件通过 Object.is 判断状态是否变化决定是否重新 render。
    render 阶段只负责计算 UI,不直接操作 DOM,真正的 DOM 更新发生在 commit 阶段。

    说说你是如何提高组件的渲染效率的?在React中如何避免不必要的render?

    React 中提高渲染效率的核心是减少不必要的 render。由于 React 默认父组件 render 会导致子组件重新执行,因此需要通过优化手段减少无效更新。

    通过拆分组件下沉state减少渲染的范围,使用memo,useMemo,useCallback,React.memo 用于缓存组件,只有 props 变化才重新渲染;useMemo 用于缓存计算结果,避免重复计算;useCallback 用于缓存函数引用,防止函数地址变化导致子组件重新渲染。通常 React.memo 需要配合 useCallback 或 useMemo 使用,保证传入子组件的 props 引用稳定,从而避免不必要的 render。

    说说React diff的原理是什么?

    React Diff 是基于 Virtual DOM 的一种启发式算法,通过两个假设优化复杂度到 O(n):不同类型节点直接替换,以及同层级节点进行比较。对于列表节点,React 通过 key 建立映射,只比较同层节点的位置变化,从而最小化 DOM 操作。Diff 过程发生在 reconciliation 阶段,最终只更新必要的 DOM 节点,提高渲染效率。

    说说对Fiber架构的理解?解决了什么问题?

    React Fiber 是 React 16 引入的新架构,主要是为了解决 React 15 中同步渲染导致的主线程阻塞问题。由于 JavaScript 线程和浏览器渲染线程是互斥的,React 15 在进行组件更新时会递归计算整棵虚拟 DOM 树,这个过程无法中断,当组件树较大时会长时间占用主线程,导致页面卡顿、动画掉帧以及用户交互延迟。Fiber 从架构角度来说是 React 对协调算法的一次重写;从数据结构角度来说,Fiber 是一种新的虚拟 DOM 节点结构,每个 Fiber 节点既代表一个组件,也代表一个可执行的任务单元。Fiber把树结构改造成链表结构,使 React 可以控制任务的执行顺序。

    Fiber 的核心思想是把一次大的更新任务拆分成多个小任务执行,也叫时间切片。React 在执行过程中会判断当前主线程是否空闲,如果时间不足就暂停任务,把控制权交还给浏览器,等空闲时再继续执行。同时 Fiber 为不同更新设置优先级,高优先级任务可以打断低优先级任务,从而提升页面的响应速度。

    在 Fiber 架构中,更新流程被拆分为 Render 阶段和 Commit 阶段,其中 Render 阶段负责 Diff 和计算更新,是可中断的;Commit 阶段负责真正的 DOM 操作和副作用执行,是同步且不可中断的,这样既保证了性能,又保证了 UI 更新的一致性。

    说说React Jsx转换成真实DOM过程?

    JSX 本质上不是 HTML,而是一种语法糖。在编译阶段会通过 Babel 转换成 React.createElement 的函数调用。createElement 不会创建真实 DOM,而是返回一个普通的 JavaScript 对象,也就是 Virtual DOM。Virtual DOM 会被转换成 Fiber 树进行调和。对比新旧 Virtual DOM,通过 Diff 算法找出需要新增、删除或更新的节点。这个阶段属于 Render 阶段,是可以中断的,不会直接操作真实 DOM。当 Diff 计算完成后,React 会进入 Commit 阶段,将变更一次性同步到真实 DOM,包括创建节点、更新属性和绑定事件。Commit 阶段是同步不可中断的,最终页面完成更新。

    说说 React 性能优化的手段有哪些?

    避免不必要的渲染,懒加载/预加载,保持state扁平化

    说说React服务端渲染怎么做?原理是什么?

    React 服务端渲染(SSR)指的是在 服务器上把 React 组件渲染成 HTML 字符串,直接返回给浏览器,然后在客户端进行事件绑定,变成可交互页面。

  • 服务端渲染 HTML,React 会:执行组件,生成 Virtual DOM,转成 HTML 字符串
  • 浏览器接收并展示
  • 客户端事件绑定:React 会:复用已有 DOM,绑定事件,恢复状态
  • Hydration 是 React 在 SSR 场景下的客户端激活过程。服务器先输出 HTML 提升首屏速度,客户端 JS 加载后不会重新创建 DOM,而是复用已有 DOM,并为其绑定事件和建立 Fiber 树,从而获得交互能力,这样可以避免重复渲染并提升性能。

    赞(0)
    未经允许不得转载:171主机测评 » React系列-2
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址