React优化手段

1 优化原则

不要过早对项目进行优化
切勿浪费精力在对整体性能提高的不多的代码上
对于关键的性能点尽早优化

react使用虚拟dom树提高性能,每次渲染并非抛弃所有重新渲染,而是借助虚拟dom计算dom树的最小修改

优化点:在计算前就判定是否需要去重新渲染

2 常用手段

使用shouldComponentUpdate来判定是否需要重新渲染是最常用的手段

2.1 单个React组件优化

  1. 在构造函数中绑定this
    对于回调函数有三种方法进行绑定:构造中、render中、箭头函数,三种方法中只有构造函数是只执行一次的(箭头函数也可以)。尽量少在render中绑定回调,因为每次绑定,对于被绑定的组件来说,传入的回调函数都是一个新对象,都会造成子组件重新渲染。
// render中绑定回调,当父组件重新渲染时,子组件一定会重新渲染
...
render(){
  return <A onClick={()=>{console.log(1)}} />
}
...
  1. render中的参数尽量使用同一对象
    由于react判定是否需要重新渲染,是通过浅层比较(地址比较)来判断的,对于值类型的变量来说没什么问题,对于引用类型的来说需要确保每次都是传入的原来的对象,否则造成性能浪费,如:
<Foo style={{color: 'red'}} />

传入的是一个对象,而每次render时该对象都是一个新的对象,会被react认为Foo组件的props每次render均发生变化,建议使用:

const fooStyle = {color: 'red'}
<Foo style={fooStyle} />
  1. 列表数据使用单独组建进行渲染
    由于列表元素渲染非常耗时,即使列表元素未发生改变,react在比较新旧列表元素时依然需要花费大量时间,建议将列表元素包装为一个组件进行单独渲染
// 新旧比较花费大量时间
{x.map(item=><p>item</p>)}
// 包装成组件后
<X content={x}/>
const X = props => <div>{props.content.map(item=><p>item</p>)}</div>

2.2 shouldComponentUpdate解析

react默认每次更新都会调用所有的生命周期函数,所以如果没有重写该周期函数,默认是直接返回true

react渲染规则:
在这里插入图片描述
从React组件的根节点开始依次按照该规则进行检查

  1. 当前节点检查scu为true,则会进行vDOMEq比较,如果比较结果为一致就停止更新,否则向下进行遍历
  2. 当前节点检查scu为false,直接停止该节点更新

起始相当于双保险:一个是scu的true和false,另一个是vDOMEq的true和false,任一为false,都会让该节点不更新,只有两个都为true才会更新该节点

2.3 PureComponent

由于大多数情况下只需要对比state和props来判断是否需要更新,所以PureComponent类实现了自己的更新方法,自动的浅比较state和props来判断是否需要更新

特别注意:对于state或props中包含引用数据类型的无法判断是否被改变了!!
如:

import React, { PureComponent } from 'react'
class MyTest2 extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      arr: []
    }
  }
  add1 = () => {
    let arr = this.state.arr
    arr.push(1)
    this.setState({ arr })
  }
  // shouldComponentUpdate() {

  // }
  render() {
    console.log('update')
    return (
      <div>{this.state.arr.length}<button onClick={this.add1}>click2</button></div>
    );
  }
}

export default MyTest2;

该组件单击后无任何变化,虽然state中的arr已经被改变了,但是页面不会被重新渲染

2.4 使用immutable(ImmutableJS)

待补充

3 其他优化点

  1. 慎用展开语法{...this.props},该语法会创建一个新对象,同时传递很多当前组件不需要的参数
  2. 在构造中进行函数this绑定
  3. 复杂页面尽量拆分
  4. 对于不变的展示组件使用const element
  5. map必须要添加key
  6. props和state尽量扁平化
  7. 使用return null来控制组件的显隐,而不是css的display:none
  8. 对于mobx+react来说,尽可能晚的解引用,能防止引用的属性变化导致父组件重渲染,进而自组建重渲染(由于mobx会观测当前组件可观测属性的变化,解引用早了,该引用变化会引起当前组件重渲染,并可能引起子组件重渲染)
// personStore中的name发生变化
// 早解引用
<A a={personStore.name}/>
// 晚解引用
<A a={personStore}/>
<think>我们正在讨论React性能优化方法和手段。根据引用内容,我们可以总结出多种优化方式,包括但不限于:使用React.memo缓存组件、合并state减少重复渲染、服务端渲染(SSR)、使用不可变数据结构(如Immutable.js)、合理使用数据请求方式以及选择合适的客户端存储等。下面将详细展开这些优化手段。 </think>以下是 React 性能优化的核心方法和手段,结合关键技术和实际应用场景: ### 一、组件级优化 1. **组件缓存** - `React.memo()`:缓存函数组件,避免无效渲染[^1] ```jsx const MemoComponent = React.memo(({ prop }) => { return <div>{prop}</div>; }); ``` - `PureComponent`:类组件的浅比较优化[^4] ```jsx class OptimizedComponent extends React.PureComponent { render() { /* 仅当 props 变化时渲染 */ } } ``` 2. **避免内联函数** 使用 `useCallback` 缓存回调函数,避免子组件重复渲染: ```jsx const handleClick = useCallback(() => { // 逻辑代码 }, [dependencies]); ``` --- ### 二、状态管理优化 1. **状态合并** React 18+ 自动批处理异步更新,减少渲染次数[^2] ```jsx // React 17需手动合并,18+自动合并 setState({ a: 1 }); setState({ b: 2 }); ``` 2. **不可变数据** 使用 Immutable.js 确保数据引用变化[^4]: ```jsx import { Map } from "immutable"; state = { count: Map({ number: 0 }) }; // 更新时创建新引用 this.setState({ count: state.count.set('number', newValue) }); ``` --- ### 三、渲染策略优化 1. **虚拟化长列表** 使用 `react-window` 实现列表虚拟化: ```jsx import { FixedSizeList } from 'react-window'; <FixedSizeList height={600} itemSize={50} itemCount={1000}> {({ index, style }) => <div style={style}>Item {index}</div>} </FixedSizeList> ``` 2. **代码分割** 动态加载非关键组件: ```jsx const LazyComponent = React.lazy(() => import('./HeavyComponent')); <Suspense fallback={<Spinner />}> <LazyComponent /> </Suspense> ``` --- ### 四、架构级优化 1. **服务端渲染(SSR)** 使用 Next.js 提升首屏性能[^3]: ```jsx export async function getServerSideProps() { const data = await fetchData(); // 服务端获取数据 return { props: { data } }; } ``` 2. **Web Worker** 将计算密集型任务移出主线程: ```jsx const worker = new Worker('heavy-task.js'); worker.postMessage(data); worker.onmessage = (e) => setResult(e.data); ``` --- ### 五、数据流优化 | 优化方向 | 技术方案 | 示例场景 | |----------------|-----------------------------|----------------------------| | **请求合并** | GraphQL/Batch Requests | 避免多次请求关联数据 | | **数据存储** | `useMemo` 缓存计算结果 | 复杂计算结果的复用[^1] | | **状态提升** | 集中状态到最近公共祖先 | 跨层级组件通信优化 | --- ### 性能检测工具 1. **React DevTools Profiler**:分析组件渲染耗时 2. **Chrome Performance Tab**:检测JS执行瓶颈 3. **Why Did You Render**:控制台输出无效渲染原因 > 关键原则:**避免不必要的渲染**比优化渲染过程更重要。通过组合使用上述手段,可显著提升复杂应用的流畅度[^1][^2][^4]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值