阅读 1835

react组件优化之React.memo

故事的开始:

我的上一个项目尝试使用了react16.0进行开发,并全线使用hooks-api,开发时由于没有注意react组件渲染机制,导致项目的性能大大低于预期。开发一时爽,完成后才发现对于react的hooks只是机械性的使用,未能得其精髓,在又一次的react16.0的学习中,看到了对于React.memo这个方法,知道了这个API是对组件渲染优化至关重要的点。

情景再现:

请看以下代码

//react 
const Child = (props) => {
  console.log('child update')
  return (
  <div>
    {props.text}
  </div>
  )
}

const App = () => {
  const [text, setText] = useState('我是文本');
  const [count, setCount] = useState(0);
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>{count}</button>
      <Child text={text}/>
    </div>
  )
}
复制代码

为什么我每点击一次按钮,控制台就回打印出'child update'?

当页面初始化完成之后,在手动点击button按钮时,请问控制台输出什么??? 答案是:每当我点击一次button,count更改后,控制台会打印出 'child update',意味着child组件重新渲染了,那么为什么count的变动会影响child组件。如果是vue用户,可能不会有这样的疑惑,因为在vue下,这种情况必不可能发生,例如:

//child 
<template>
	<div>{{text}}</div>
</template>

export default {
    props: {
    	text: {
        	type: String,
        	default: ''
        }
    },
    mounted() {
    	console.log('child mounted')
    },
    updated() {
    	console.log('child update')
    }
}
// parent
<template>
	<div>
    	<button @click='countAdd'>
        	{{count}}
        </button>
        <Child :text='text'/>
    </div>
</template>

export default {
    data() {
    	return {
            count: 0,
            text: 'child'
        }
    },
    methods: {
    	countAdd() {
        	this.count ++;
        }
    }
    mounted() {
    	console.log('child mounted')
    },
    updated() {
    	console.log('child update')
    }
}
复制代码

对于vue来说,这很好解释,child依赖parent传入的text,parent内count的变更,而text没有变动,所以child组件无需更新。那么问题回到最初,在react内父组件的state变更,没有依赖变更数据的子组件为什么会重新渲染。

数据的单向流动

对于vue来说,因为使用的是数据劫持的方式,所以可以很方便的知道哪里的数据进行了更新,因为知道数据改变的具体位置,那么组件的重新渲染是可控的,即在框架内部,vue自己就已经优化了组件渲染的时机,防止单一数据变动而引起的大规模的组件渲染,造成不必要的性能浪费,但是 React是单向数据流,数据主要从父节点传递到子节点(通过props)。 如果顶层(父级)的某个props改变了,React会重渲染所有的子节点,但是这样就会造成比较多的性能浪费,在react 16以下 class组件中 我们可以使用shouldComponentDidMount或者PureComponent来控制组件的渲染,但是在16.0以上函数式组件中,我们应该如何去优化组件渲染呢,标题来了:React.memo

React.memo

该api使得组件仅在它的 props 发生改变的时候进行重新渲染。通常来说,在组件树中 React 组件,只要有变化就会
走一遍渲染流程。但是通过React.memo(),我们可以仅仅让某些组件进行渲染。
复制代码

所以对于上面重复渲染子组件的方案,仅仅需要小小改造一下就行

//react 
import {memo} from 'react';
const Child = memo((props) => {
  console.log('child update')
  return (
  <div>
    {props.text}
  </div>
  )
})
复制代码

改造完成,多次点击button控制台已经不会再像之前一样多次打印'child update'了,到此本次react组件优化结束了。

后话:

其实以上的问题,解决起来是很快速的,百度一下,1分钟搞定,但是在问题之下,有更多需要我们去积极了解的内在因素,业务代码千篇一律,但是内在的编码思想确实我们需要去深刻思考。

文章分类
前端
文章标签