乐趣区

关于前端:React-知识回顾-优化篇

接下来对 React 性能相干的问题进行常识回顾。

目录概览

  • React 代码复用

    • Render props
    • 高阶函数、高阶组件别离是什么?
  • React 性能优化
  • 父组件在执行 render 时会不会触发子组件的 render 事件?如果会该怎么防止?
  • 渲染列表为啥要用 key?
  • 虚构 dom 是如何晋升性能的
  • 简述 React Diffing 算法
  • 异步组件怎么应用?
  • JSX 是如何编译为 js 代码的?
  • 怎么对组件的参数做类型束缚呢?

React 代码复用

  • Render Props
  • 高阶组件 (HOC)
  • 自定义 Hooks
  • Mixins (已被 React 废除)

Render props

Render props 是一种在 React 组件之间共享代码的简略技术。具体的行为是:

  1. 子组件接管一个用于渲染指定视图的 prop 属性,该属性的类型是函数。
  2. 父组件在组件外部定义该函数后,将函数的引入传给子组件
  3. 子组件将组件外部 state 作为实参传给从里面传来的函数,并将函数的返回后果渲染在指定的视图区域。
// 组件应用
<Mouse render={(x, y) => <span>x: {x}, y: {y}</span>} />

// 组件外部大抵实现
class Mouse extends React.Component {state = { x: 0, y: 0};

  render() {
    return (
      <section>
        <header> 头部信息 </header>
        <main>{this.props.render(this.state)}</main>
        <footer> 底部信息 </footer>
      </section>
    );
  }
}

精确来说 Render props 是一个用于告知组件须要渲染什么内容的函数属性。props 的命名能够由本人定义,比方用于在内容区域渲染的 prop 名能够叫 render,同时还能够再接管一个 renderHead 的 prop 用于渲染头部的信息。

高阶函数、高阶组件别离是什么?

高阶函数 就是 接管其它函数作为参数 的函数就称之为高阶函数,像数组的 mapsortfilter 都是高阶函数。

高阶组件(Higher-order component, HOC) 是 React 用于复用组件逻辑的一种高级技巧。它具体的行为是:

函数 接管一个组件作为参数 ,在函数体内 定义一个新组件 ,新组件内 编写可复用的逻辑 并利用到参数组件中。最初再将 新组件作为函数的返回值 return 进来。
redux 中的 connect 函数就是一个高阶组件。

React 性能优化

  1. 比照 props/state 新旧值的变动来决定是否渲染组件,参见:父组件在执行 render 时会不会触发子组件的 render 事件?如果会该怎么防止?
  2. 列表渲染时每项增加惟一的 key。参见:渲染列表为啥要用 key?
  3. 定时器、DOM 事件等在组件销毁时一起销毁,从而防止内存泄露。
  4. 代码宰割,应用异步组件。
  5. Hooks 应用 useMemo 缓存上一次计算的后果,防止反复计算值。

父组件在执行 render 时会不会触发子组件的 render 事件?如果会该怎么防止?

如果父组件渲染后,子组件接管的 props 也跟着产生了扭转,那么默认状况下会触发子组件的渲染。

若子组件承受的 props 没有产生扭转,那就得判断子组件的情况。

如果子组件是继承于 Component 申明的组件,并且没有应用 shouldComponentUpdate 做防止反复渲染的解决,那么子组件会触发 render 事件。

为了防止反复渲染,类组件能够应用 shouldComponentUpdate 来决定是否进行渲染。也能够将继承于 Component 组件改为继承 PureComponment,该组件会浅比照 Props 是否进行扭转,从而决定是否渲染组件。

如果是函数组件,能够通过 React.memo 来对函数组件进行缓存。

渲染列表为啥要用 key?

渲染列表时,如果不给列表子项传 key 的话,React 将默认应用 index 作为 key,同时会在控制台收回正告。

key 在兄弟节点之间必须惟一,要防止应用数组下标 index 作为 key。因为应用数组下标作为 `key 时,若数组的程序产生了扭转,将会影响 Diffing 算法的效率。

若列表的节点是组件的话,还可能会影响组件的 state 数据。因为组件实例是基于 key 来决定是否更新与复用。当程序产生了变动,则 key 也会相应得被批改,从而导致子组件间的数据错乱。

React 应用的 Diffing 算法是通过 tagkey 判断是否是同一个元素(sameNode)。应用惟一的 key 有助于 React 辨认哪些元素产生扭转,如节点增加或删除。这样有助于缩小渲染次数,从而优化性能。

如果数组中的数据没有惟一的 key,能够引入 shortid 事后给数组中每项数据生成惟一的 id

const shortid = require('shortid');

function addId(data) {
  return {
    ...data,
    id: shortid.generate(),}
}

const newList = list.map(addId);

若确定没有列表的程序不会发生变化同时没有其余惟一的 key 来标识列表项时能力应用数组的下标。

虚构 dom 是如何晋升性能的

当组件触发更新时,虚构 DOM 通过 Diffing 算法比对新旧节点的变动以决定是否渲染 DOM 节点,从而缩小渲染晋升性能。因为批改实在 DOM 所消耗的性能远比操作 JavaScript 多几倍,因而应用虚构 DOM 在渲染性能上会高效的多。

简述 React Diffing 算法

Diffing 算法(Diffing Algorithm) 会先比拟两个根元素的变动:

  1. 节点类型变动 时,将会卸载原有的树而建设新树。如父节点 <div> 标签被批改为 <section> 标签,则它们本身及 children 下的节点都会被从新渲染。
  2. DOM 节点类型雷同 时,保留雷同的 DOM 节点,仅更新产生扭转的属性。
  3. 组件类型雷同时,组件更新时组件实例放弃不变,React 将更新组件实例的 props, 并调用生命周期 componentWillReceiveProps()componentwillupdate(),最初再调用 render。若 render 中还有子组件,将递归触发 Diff。
  4. 列表节点发生变化,列表项没有设置 key 时, 那么 Diffing 算法会一一比照节点的变动。如果是尾部新增节点,那 Diff 算法会 Diff 到列表开端,仅新增元素即可,不会有其余的性能损耗。若新增的数据不在数组的尾部而是在两头,那么 Diffing 算法比拟到两头时判断出节点发生变化,将会抛弃前面所有节点并从新渲染。
  5. 列表节点发生变化,列表项有设置 key 时, React 能够通过 key 来匹配新旧节点间的对应关系,能够很快实现 Diff 并防止反复渲染的问题。

异步组件怎么应用?

  1. 通过动静 import() 语法对组件代码进行宰割。
  2. 应用 React.lazy 函数,联合 import() 语法引入动静组件。在组件首次渲染时,会主动导入蕴含 MyComponent 的包。

    const MyComponent = React.lazy(() => import('./MyComponent'));
  3. React.Suspense 组件中渲染 lazy 组件,同时能够应用 fallback 做优雅降级(增加 loading 成果):

    <React.Suspense fallback={<div>Loading...</div>}>
      <MyComponent />
    </React.Suspense>
  4. 封装一个谬误捕捉组件(比方组件命名为 MyErrorBoundary),组件内通过生命周期 getDerivedStateFromError 捕捉错误信息。当异步组件加载失败时,将捕捉到谬误信息处理后给用户做谬误提醒性能。

    <MyErrorBoundary>
       <React.Suspense fallback={<div>Loading...</div>}>
        <MyComponent />
      </React.Suspense>
    </MyErrorBoundary>

JSX 是如何编译为 js 代码的?

在 React v17 之前,JSX 会被编译为 React.createElement(component, props, ...children) 函数,执行会返回 vnodevnode 通过 patch 之类的办法渲染到页面。

React v17 之后更新了 JSX 转换规则。新的 JSX 转换不会将 JSX 转换为 React.createElement,而是主动从 React 的 package 中引入新的入口函数 (react/jsx-runtime) 并调用。这意味着咱们不必在每个组件文件中显式引入 React

怎么对组件的参数做类型束缚呢?

要对组件的参数做类型束缚的话,能够引入 prop-types 来配置对应的 propTypes 属性。
FlowTypesScript 则能够对整个利用做类型查看。


  • 上一篇文章: React 常识回顾 (应用篇)
  • 本文原文地址: React 常识回顾 (优化篇)
  • 前端面试笔记: front-end-lab
退出移动版