• React 性能优化注意事项
  • 发布于 2个月前
  • 233 热度
    0 评论
由于全部使用的函数式组件,每次 setState 的时候,都会导致 re-render。而 React 是父组件更新,子组件也会跟着更新,所以需要做一些优化。

一. 子组件使用 memo 包裹
父组件
function App() {
  const [count, setCount] = useState(0)

  return (
    <>  
      <div>{count}</div>
      <button onClick={() => setCount(count + 1)}>add</button>
      <Foo />
    </>
  )
}
子组件
import { memo } from "react"
const Index = () => {
  console.log('re-render');
 
  return <div>子组件</div>
}
export default memo(Index)

二. 传递给子组件的函数使用 useCallback 包裹
如果不传递给子组件,可以不使用 useCallback 包裹。因为 re-render 时只是重新定义了一遍,函数内部并没有执行。为什么要用 useCallback 包裹,因为 re-render 时前后创建的两个函数引用地址并不一样,Object.is 比较是否相同时会返回 false。

父组件
import { useCallback, useState } from 'react'
import Foo from '@/components/foo'
import './App.css'
// 堆代码 duidaima.com
function App() {
  const request = useCallback(() => {
    setTimeout(() => {
      console.log('请求');
    }, 10)
  }, [])

  // const request = () => {
  //   setTimeout(() => {
  //     console.log('请求');
  //   }, 10)
  // }
  const [count, setCount] = useState(0)
  return (
    <> 
      <button onClick={()=>setCount(count + 1)}>{count}</button>
      <Foo request={request} />
    </>
  )
}
export default App
子组件
import { memo } from "react"
interface Props {
  request: () => void
}
const Index = (props: Props) => {
  console.log('re-render');
  return (
    <button onClick={props.request}>按钮</button>
  )
}
export default memo(Index)

三 传递给子组件的引用数据类型需要使用 useMemo 包裹

其实和上面说的传递函数给组件,函数要用 useCallback 包裹起来是同一个道理。函数也是引用数据类型,是一个特殊的对象!

父组件
import { useCallback, useMemo, useState } from 'react'
import Foo from '@/components/foo'
import './App.css'

function App() {
  const obj = useMemo(() => ({
    name: 'xiaowang',
    age: 19
  }), [])

  const [count, setCount] = useState(0)

  return (
    <> 
      <button onClick={()=>setCount(count + 1)}>{count}</button>
      <Foo obj={obj}/>
    </>
  )
}

export default App
子组件
import { memo } from "react"

interface Props {
  obj: {
    name: string,
    age: number
  }
}
const Index = (props: Props) => {
  console.log('re-render');
  
  return (
    <button>按钮</button>
  )
}

export default memo(Index)
四. hook 使用 useMemo 包裹
为什么 hook 要使用 useMemo 包裹?因为我们使用 hook 本质上是在调用一个函数执行的计算结果。每次 re-render 的时候,都去执行一下 hook 函数的话,可能会造成性能上的损失。所以可以使用 useMemo 将函数执行的计算结果缓存起来。
组件
function App() {
  const list = usePow([1,2,3,4])
  console.log(list);
  const list2 = usePow([1,2])
  console.log(list2);
  const [count, setCount] = useState(0)

  return (
    <> 
      <button onClick={()=>setCount(count + 1)}>{count}</button>
      <Foo />
    </>
  )
}
hook
import { useMemo } from 'react';

export default (list: number[]) => {
  return useMemo(() => list.map(num => {
    console.log('hook 执行了');
    return Math.pow(num, 2)
  }), [])
}


用户评论