react基本功

useLayoutEffect

useLayoutEffect 用于在浏览器重新绘制屏幕之前同步执行代码。它与 useEffect 相同,但执行时机不同。

主要特点
  • 执行时机useLayoutEffect 在 DOM 更新完成后同步执行,但在浏览器绘制之前。这使得它可以在浏览器渲染之前读取和修改 DOM,避免视觉上的闪烁或不一致。
  • 适用场景:主要用于需要同步调整布局的副作用操作,例如测量 DOM 元素的尺寸(如高度、宽度、滚动位置等)并根据这些值进行渲染。
  • 性能影响:由于 useLayoutEffect 阻塞了浏览器的绘制,如果执行复杂或耗时的操作,可能会导致性能问题或视觉卡顿。
useEffect 的区别
  • 执行时间
    • useEffect:在浏览器绘制之后异步执行。
    • useLayoutEffect:在浏览器绘制之前同步执行。
注意事项
  • useLayoutEffect 在服务器端渲染(SSR)中不会执行,因此在 SSR 场景下需要谨慎使用。
  • 尽量优先使用 useEffect,因为 useLayoutEffect 可能会影响性能。

总之,useLayoutEffect 是一个强大的工具,但应仅在需要同步处理 DOM 布局时使用。

useEffect

useEffect 可以用来实现类似类组件生命周期方法的功能。通过合理配置 ,可以模拟类组件中的 componentDidMountcomponentDidUpdatecomponentWillUnmount 等生命周期方法。

总结

但需要注意的是,useEffect 的执行时机是异步的,如果需要在浏览器绘制之前同步操作 DOM,可以使用 useLayoutEffect

useCallback和useMemo的区别

1. useMemo

useMemo 用于缓存计算结果,避免在组件重新渲染时重复执行复杂的计算逻辑。

特点
  • 用途:缓存计算结果。
2. useCallback

useCallback 用于缓存函数,避免在组件重新渲染时创建新的函数引用。

特点
  • 用途:缓存函数引用。
  • 执行时机:每次组件渲染时都会执行,但如果依赖项没有变化,则返回缓存的函数引用。
使用场景
  • 当需要将函数作为依赖项传递给子组件时,为了避免子组件因函数引用变化而重新渲染。
示例
import React, { useState, useCallback } from 'react';

function MyComponent() {
  const [count, setCount] = useState(0);

  // 缓存函数引用
  const handleClick = useCallback(() => {
    console.log("点击按钮,当前计数:", count);
  }, [count]); // 只有 count 变化时重新创建函数

  return (
    <div>
      <p>计数: {count}</p>
      <button onClick={handleClick}>点击</button>
    </div>
  );
}

在这个例子中,handleClick 函数被缓存,只有当 count 发生变化时才会重新创建一个新的函数引用。


3. 使用建议
  • useMemo
    • 仅在计算逻辑复杂且对性能有明显影响时使用。
    • 如果计算逻辑简单,直接在渲染逻辑中执行即可,避免过度优化。
  • useCallback
    • 适用于需要将函数传递给子组件的场景。
    • 如果子组件使用了 React.memoshouldComponentUpdateuseCallback 可以避免因函数引用变化导致的子组件不必要的重新渲染。

总结

useMemouseCallback 都是用于优化性能的 Hook,但它们的用途不同:

  • useMemo 用于缓存计算结果,避免重复计算。
  • useCallback 用于缓存函数引用,避免因函数引用变化导致的子组件重新渲染。

Fiber架构出现之前 react 存在的问题

在 React Fiber 架构出现之前,React 主要存在以下问题:

  1. 同步渲染导致的卡顿
    React 15 及之前的版本采用同步的 Stack 架构进行渲染。当组件状态更新时,React 会立即重新构建整个虚拟 DOM 树,并与之前的虚拟 DOM 树进行对比(diff),然后一次性将所有差异应用到真实 DOM 上。如果组件树较大或更新频繁,这个过程会阻塞主线程,导致用户交互和动画任务无法及时响应,页面出现卡顿。

  2. 递归调用无法中断
    旧版本的渲染过程是基于递归实现的,一旦开始渲染,整个过程无法中断,必须等到所有任务完成。这使得浏览器无法在渲染过程中处理其他高优先级任务,例如用户的点击或输入事件。

  3. 缺乏任务优先级调度
    在 React 15 及之前的版本中,所有更新任务的优先级是相同的,无法根据任务的紧急程度(如用户交互、动画等)进行动态调度。这导致即使某些任务对用户体验至关重要,也会被同步渲染过程阻塞。

  4. 错误处理能力有限
    在旧版本中,如果渲染过程中发生错误,整个应用可能会崩溃,因为错误无法被有效隔离。

为了解决这些问题,React 16 引入了 Fiber 架构,其核心改进包括:

  • 可中断的 异步 渲染:Fiber 将渲染任务分解为多个小任务单元,允许在浏览器空闲时暂停和恢复渲染。
  • 优先级调度:引入了任务优先级机制,高优先级任务(如用户交互)可以优先执行。
  • 增量渲染:支持分批次将更新应用到真实 DOM,减少重排和重绘的开销。
  • 错误边界:引入了错误边界机制,允许捕获组件树中的错误并显示备用 UI,而不会导致整个应用崩溃。

双缓冲技术

React Fiber使用了类似于图形渲染中的双缓冲技术。这意味着在构建新的UI树时,React会同时在内存中维护两棵树:当前屏幕上显示的树(current tree)和正在构建的树(work-in-progress tree)。只有当新的树完全构建完成后,它才会被一次性地渲染到屏幕上,从而实现更加流畅的用户体验。

虚拟DOM是什么

虚拟 DOM 的工作原理

  1. 构建虚拟 DOM
    当组件首次渲染时,框架会根据组件的 JSX 或模板生成一个虚拟 DOM 树。这个虚拟 DOM 树是一个 JavaScript 对象,它包含了组件的结构、属性和内容。

    const virtualDOM = <div className="container">
        <h1>Hello, World!</h1>
        <p>This is a paragraph.</p>
    </div>;
    

    在内存中,虚拟 DOM 可能是一个类似这样的对象:

    {
        type: "div",
        props: { className: "container" },
        children: [
            {
                type: "h1",
                props: {},
                children: ["Hello, World!"]
            },
            {
                type: "p",
                props: {},
                children: ["This is a paragraph."]
            }
        ]
    }
    

虚拟 DOM的数量

在 React 应用中,虚拟 DOM 的数量并不是固定的:

  1. 虚拟 DOM 的数量
    当状态发生变化时,React 会重新生成一个新的虚拟 DOM 树,并通过 Diff 算法比较新旧虚拟 DOM 树的差异。因此,虚拟 DOM 的数量取决于组件的状态变化频率和组件树的大小。

Hook 必须在函数组件或另一个 Hook 中调用吗

这是 React 的设计规则,也是 Hooks 能够正常工作的前提条件。

总结

React Hooks 必须在函数组件或自定义 Hook 中调用,这是为了确保 Hooks 的调用顺序一致,并且能够正确管理状态和副作用。违反这些规则会导致错误或不可预测的行为。

受控组件和非受控组件

在 React 中,表单元素(如 <input><textarea><select> 等)可以通过两种方式管理:受控组件(Controlled Components)非受控组件(Uncontrolled Components)

1. 受控组件(Controlled Components)

受控组件是指表单元素的值由 React 的状态(state)控制的组件。在这种模式下,表单元素的值通过 value 属性绑定到 React 的状态,并通过事件处理器(如 onChange)更新状态。

特点:
  • 状态同步:表单元素的值始终与 React 的状态保持一致。
  • 单向数据流:数据从 React 状态流向表单元素,用户输入会触发事件处理器来更新状态。
  • 易于管理:适合需要严格控制表单数据的场景,如表单校验、动态更新等。
2. 非受控组件(Uncontrolled Components)

非受控组件是指表单元素的值不由 React 的状态控制,而是直接由 DOM 元素管理的组件。在这种模式下,表单元素的值通过 ref 获取,而不是通过 value 属性绑定到 React 的状态。

特点:
  • 性能优势:在某些场景下,非受控组件的性能可能更好,因为不需要频繁更新 React 状态。
  • 适合简单场景:适合不需要严格控制表单数据的场景,如简单的输入框。
使用场景:
  1. 受控组件

    • 表单校验:需要实时校验用户输入。
    • 动态更新:需要根据用户输入动态更新 UI 或状态。
    • 复杂表单:需要严格控制表单数据的场景。
    • 默认值动态变化:表单的初始值可能来自外部状态或 API。
  2. 非受控组件

    • 简单表单:表单逻辑简单,不需要实时校验。
    • 性能优化:在某些场景下,非受控组件的性能更好。
    • 外部库集成:某些第三方库可能更适合非受控模式。
注意事项:
  1. 受控组件的陷阱

    • 如果忘记绑定 valueonChange,表单元素将无法正常工作。
    • 受控组件需要频繁更新状态,可能会导致性能问题(尤其是在大型表单中)。
  2. 非受控组件的限制

    • 非受控组件的值只能通过 ref 获取,无法通过 React 的状态直接访问。
    • 非受控组件的初始值只能通过 defaultValuedefaultChecked 设置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值