提到React的性能优化,大家的脑海中应该会呈现useMemoMemouseCallBack这些词。这些都是官网提供的性能优化hooks,的确也解决了咱们日常工作中遇到的大部分性能优化问题。

在看了某网红(Dan Abramov)的文章后,我想和大家分享两种不应用这些hooks解决性能问题的形式。
让咱们先来看个例子:

import {useState}from 'react';const TimeMashine = ()=>{  const now = Date.now();  console.log('111')  return (<p>I am time mashine</p>)}const App = ()=>{  const [count,setCount]=useState(0);  const onClick=()=>{    const newCount=count+1;    setCount(newCount)  }  return (<div>    <button onClick={onClick}>click me</button>    <p>I clicked button {count} times</p>    <TimeMashine/>  </div>)}export default App

这个组件有着重大的性能问题,其中TimeMashine组件在按钮被点击的时候都会反复渲染。除了官网提供的Memo等优化形式,这里有还有两种形式能够做优化。

一、state地位调整

const App = ()=>{  const [count,setCount]=useState(0);  const onClick=()=>{    const newCount=count+1;    setCount(newCount)  }  return (<div>    <button onClick={onClick}>click me</button>    <p>I clicked button {count} times</p>    <TimeMashine/>  </div>)}

认真看这段代码,咱们会发现这个按钮点击只是更新p标签中的文本内容,TimeMashie组件其实并不关怀点击事件。

import { useState }from 'react';const TimeMashine = ()=>{  const now = Date.now();  console.log('I am updated')  return (<p>I am time mashine</p>)}const Text = ()=>{  const [count,setCount]=useState(0);  const onClick=()=>{    const newCount=count+1;    setCount(newCount)  }  return (<>    <button onClick={onClick}>click me</button>    <p>I clicked button {count} times</p>    </>)}const App = ()=>{  return (<div>   <Text/>    <TimeMashine/>  </div>)}export default App

二、内容晋升

让我来看另外一种状况

import {useState}from 'react';const TimeMashine = ()=>{  const now = Date.now();  console.log('I am updated')  return (<p>I am time mashine</p>)}const App = ()=>{  const [count,setCount]=useState(0);  const onClick=()=>{    const newCount=count+1;    setCount(newCount)  }  return (<div>      <p>I clicked button {count} times</p>      <div>        <button onClick={onClick}>click me</button>        <TimeMashine/>      </div>  </div>)}export default App

能够看到 I clicked button {count} times被晋升到了里面,显然不能再用形式一的方法来解决。

import {useState}from 'react';const TimeMashine = ()=>{  const now = Date.now();  console.log('I am updated')  return (<p>I am time mashine</p>)}const TimeAndText = ({children})=>{  const [count,setCount]=useState(0);  const onClick=()=>{    const newCount=count+1;    setCount(newCount)  }  return (<>      <p>I clicked button {count} times</p>      <div>        <button onClick={onClick}>click me</button>        {children}      </div>  </>)}const App = ()=>{  return (      <TimeAndText>        <TimeMashine/>      </TimeAndText>)}export default App

咱们把按钮文本提取为独立的组件,TimMashine作为依赖传入TimeAndtext组件。当点击按钮的时候,TimeAndtext会更新,然而children作为依赖没有变动所以不会更新。
Dan认为这种模式自身并不是为了进步性能而写的,这种模式的目标是为了缩小组件的props参数数量而产生,然而意外的解决了性能上的问题。这个问题的确值得咱们思考。

参考

  • Before You memo -- Dan Abramov