react项目优化

前言

传统的Diff算法O(N3),React Diff基于三大前提将复杂度降为O(N)

1.tree diff,跨层dom操作比较少,结构不同直接销毁
2.component diff,相同类型节点有相同树形结构,只做更新,不同类型直接销毁
3.element diff,同层子元素根据唯一标识做区分

一.代码优化

1.key

设置唯一稳定的key
render() {
  return (
    
this.state.user.map(item =>
{item.name}
)
) }

2.节点内容

节点类型分两大类,一类是DOM元素类型(如div,span),另一类是React组件

Dom元素比较属性和内容
this.handleClick()}>变化前
... // 变化后属性和内容都变化了
this.handleClick()}>变化后

注意引用类型的比较

 {color: 'red'} === {color: 'red'}  // false
 var fun1 = () => {}
 var fun2 = () => {}
 fun1 === fun2  // false

优化后,属性指向都不变

const style = {color: 'red'}
...
constructor(props) {
  super(props)
  this.handleClick = this.handleClick.bind(this)
}
...
render() {
  return {
    
更改后
} }

redux版本优化前,

 onRemoveTodo(item.id)}
  ...

...

redux版本优化后

// 方法1

...

const mapDispatchToProps = (dispatch,ownProps) => ({
  onRemoveTodo: ownProps.onRemoveTodo(ownProps.id)),
})

// 方法2

...
const mapDispatchToProps = (dispatch,ownProps) => ({
  onRemoveTodo: () => dispatch(onRemoveTodo(ownProps.id)),
})

3.shouldComponentUpdate(nextProps,nextState)

为了避免浪费多余的渲染,return false可以阻止组件的更新
shouldComponentUpdate(nextProps,nextState) {
  return nextProps.isChange !== this.props.isChange   // true or false
}

PureComponent类内部也是用了shouldComponentUpdate

// PureComponent内部
if (this._compositeType === CompositeTypes.PureClass) {
  shouldUpdate = !shallowEqual(prevProps, nextProps)
  || !shallowEqual(inst.state, nextStat e);
}
return shouldUpdate;

shallowEqual(浅比较),只做简单类型的判断。

state = {
  arr = [1,2,3,4,5]
}
shouldComponentUpdate(nextProps,nextState) {
  return nextState.arr !== this.state.nextState // false
}
handleClick = () => {
 const { arr } = this.state
  arr.push(6)
    this.setState({
      arr,
  })
}

render () {
  ...
}

解决方法deepEqual,但如果变量嵌套深会对性能有消耗

二.工具使用

1.immutable(一种不可更改的数据)

网上一般写法

import { is } from 'immutable' 
...
  shouldComponentUpdate = (nextProps = {} , nextState = {}) => {
    if(Object.keys(this.props).length !== Object.keys(nextProps).length ||
        Object.keys(this.state).length !== Object.keys(nextState).length
    ) {
      return true
    }
    for(const key in nextProps) {
      if(this.props[key] !== nextProps[key] || !is(this.props[key],nextProps[key])) {
        return true
      }
    }
    for(const key in nextState) {
      if(this.state[key] !== nextState[key] || !is(this.state[key],nextState[key])) {
        return true
      }
    }
    return false
  }
...

我项目中优化前后对比


  shouldComponentUpdate = (nextProps = {} , nextState = {}) => {
    if(!is(nextState,this.state)) {
      return true
    }
    return false
  }
优化前.png

优化后.png

使用了结构共享,避免deepCopy,可节省内存

2.reselect

一种选择器中间件,认为输入参数state相同,就没必要进行计算,直接抽取以往的值

const mapState = (state)=>({
  todos:state.todos,
  filter:state.filter,
  visibleTodos:getVisibleTodos(state.todos,state.filter)
});
//selector.js
export const todosSelector = (state) => state.todos;
export const filterSelector = (state) => state.filter;
export const visibleTodosSelector = createSelector(
  [todosSelector,filterSelector],
  (todos,filter)=>{return getVisibleTodos(todos,filter)}  //这里假设已经定义一个getVisibleTodos函数用来返回要显示哪些todo项
 );
 
//container.js
import {visibleTodosSelector}
const mapState = (state)=>({
  todos:visibleTodosSelector(state)
});

3.其他

少用{...props}
适当拆分组件
压缩,合并,commonChunksPulgin(webpack4里面移除了commonChunksPulgin插件,放在了config.optimization里面)

css预处理语言写法,防止多余编译

三.Fiber架构迁移

以往的react渲染是一气呵成,不能打断,同步渲染计算大的话容易阻塞UI线程。
react16后提出Fiber,使react从Stack reconciler转变为fiber reconciler


Fiber两个Phase.png

将渲染分割成多个事务,使得以往的栈结构可以定制优先级,暂停,复用,其中第一个阶段是可以随时被打断的阶段,这使得某部分旧的生命周期函数造成不安全的危害
componentWillMount
componentWillReceiveProps
componentWillUpdate
用其它生命周期函数再结合两个新的生命周期函数,足以替代它们的业务场景

getDerivedStateFromProps(nextProps, prevState)

  static getDerivedStateFromProps(nextProps, prevState) {
    if (nextProps.selectCodeId !== prevState.codeId) {
      return {
        codeId: nextProps.selectCodeId,
        first: false,
      };
    }
    return null;
  }

getDerivedStateFromProps没有附加渲染的情况下更新状态的唯一方法,可以用来替代componentWillReceiveProps

getSnapshotBeforeUpdate(prevProps, prevState)

export default class ScrollingList extends Component {
  constructor(props) {
    super(props)
    this.scrollRef = null
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    if (prevProps.list.length < this.props.list.length) {
      return (
        this.scrollRef.scrollHeight - this.scrollRef.scrollTop
      );
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    if (snapshot !== null) {
      this.scrollRef.scrollTop =
        this.scrollRef.scrollHeight - snapshot;
    }
  }

  render() {
    return (
      ....
    );
  }


}
react16.png

你可能感兴趣的:(react项目优化)