性能优化小技巧合集

性能优化

 1. list渲染使用唯一-key  --- 加快DOM Diff更新
 2. 超列表使用虚拟滚动     --- 减少无意义列表渲染,提升用户体验
 3. 不使用内连对象        --- 避免对象饮用重复创建导致组件render
 4. JSX中直接引入        --- 加快svg展示速度 可自定义svg属性

首先是列表渲染使用唯一 key

我们都知道 React 在执行 Diff 算法时,会用到元素的 key 属性,它可以帮助 React 定位更改、添加或删除的项目,
在重新 render 的时候尽可能少得更新 DOM 内容,加快更新速度。
当然 key 值的设置也是有一定要求的,那就是要保证稳定性。
对于一个列表组件来说,每一个列表项的 key 应该是唯一且固定的,比如每个列表项数据固定的 idimport React from "react";

export default class MyComponent extends React.Component {
    render() {
        const List = data.map(item => {
            return <li key={item.id}>{item.name}</li>;
        })
        return (
            <ul>
                {List}
            </ul>
        )
    }
}

除了像 id 这样列表数据已有的单一字段,也可以使用多个字段
,通过一些简单的组合或者算法,生成一个唯一且固定的值作为 key 的值。
比如我们可以通过列表数据的 type 字段以及 name 字段唯一确定一个列表项。

const List = data.map(item => {
    return <li key={`${item.type}_${item.name}`}>{item.name}</li>;
})


如果我们找不到 id 或者多个字段确定唯一列表项的话,一些情况下我们也可以使
用列表数据的索引来作为 key 值,比如:列表项不会被重新排序或过滤;
列表顶部或中间不会插入或删除列表项等
(否则 React 可能会因为索引导致更新效率极大降低甚至数据更新错误)。

const List = data.map((item, index) => {
    return <li key={index}>{item.name}</li>;
})

第二点是长列表使用虚拟滚动,相信大家在平时开发时经常会遇到长列表,如会话列表、订单列表等等,列表项成百上千甚至更多,页面在渲染这些列表项时非常耗时,有时候页面可能都无法与用户交互,出现假死的情况,用户体验很不好。

import React from "react";
import "./index.css";

// 列表项
const Row = ({ index, style }) => (
    <div className={index % 2 ? "ListItemOdd" : "ListItemEven"}>
        Row {index}
    </div>
);

// 定义一个长度为 1000 的数组用于生成列表项
const arr = new Array(10000).fill('*');
let startRender = 0;
let finishRender = 0;
// 列表
class App extends React.Component {
    componentDidMount() {
        finishRender = new Date().getTime();
        console.log('renderTime', (finishRender - startRender)/1000, 's');
    }

    render() {
        startRender = new Date().getTime();
        return (
            <div className="List">
                {arr.map((el, index) => <Row key={index} index={index} />) }
            </div>
        )
    }
}

export default App;



我们以 npm 包 react-window 来举例,仍然是 1 万个列表项,我们用 react-window 提供的 FixedSizeList 组件作为列表项的父组件,并且为父组件提供列表的宽高、列表项高度以及列表项数量等数据:

import React from "react"
import { FixedSizeList as List } from "react-window"

import "./index.css"

// 列表项
const Row = ({ index, style }) => (
    <div className={index % 2 ? "ListItemOdd" : "ListItemEven"} style={style}>
        Row {index}
    </div>
);

// 定义一个长度为 1000 的数组用于生成列表项
const arr = new Array(10000).fill('*')
let startRender = 0
let finishRender = 0

// 列表
class App extends React.Component {
    componentDidMount() {
        finishRender = new Date().getTime()
        console.log('renderTime', (finishRender - startRender)/1000, 's')
    }
    render() {
        startRender = new Date().getTime()
        return (
            <List
                className="List"
                height={200}
                itemCount={arr.length}
                itemSize={35}
                width={300}
            >
                {Row}
            </List>
        );
    }
}

export default App;


不使用内联对象

我们可以看到 OtherComponent 接收的 props 中还有对象 extraProps,也会出现上面多次创建对象引用的问题,但由于使用了 App 的 props.title 值,我们无法像上述的解决办法一样,在组件外初始化一次对象 extraProps。

那么这时我们可以使用 ES6 扩展运算符,将 extraProps 对象解构,让 OtherComponent 接收到的 props 为基本类型 String,如果 props.title 的值没有变化,则通过浅比较一样不会触发 render:

import React from "react"
import OtherComponent from './OtherComponent'

const styles = { paddingTop: 10 }
const App = props => {
    // props.title 为 String 类型
    const extraProps = { title: props.title }
    return <OtherComponent
        style={styles}
        {...extraProps}
    />
}

在 JSX 中直接引入 svg。大家可能经常会在项目中使用到 svg 格式的图片


import React from 'react'

const Thumb = props => {
    return (
        <svg
            xmlns="http://www.w3.org/2000/svg"
            width="24"
            height="24"
            viewBox="0 0 24 24"
            fill="none"
            stroke="#000000"
            strokeWidth="2"
            strokeLinecap="round"
            strokeLinejoin="round"
            {...props} >
            <path d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3"></path>
        </svg>
    );
}

export default Thumb;



class App extends React.Component {
    render() {
        return (
            <div className="content">
                <p>This is content</p>
                 <p className="row" >
                    <span> 使用 img 标签引入 svg:</span>
                     <img
                        className="thumb"
                        alt="thumb"
                        src="https://my.app.com/cdn/thumb.svg"
                    /
                </p
                <p className="row" >
                    <span>react 无状态组件引入 svg:</span>
                    <Thumb/>
                </p>
                <p className="row" >
                    <span> 更改属性后的 svg:</span>
                    <Thumb stroke="#ff6044" />
                </p>
            </div>
        )
    }
}

export default App;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值