React 性能优化

2025-06-07

React 性能优化

嘿伙计们,我希望你们都过得很好。

时隔许久,我又开始专注于在 dev.to 上撰写文章。在本文中,我想介绍一种避免 React 组件重新渲染的方法。

#1 避免向子组件传递不必要的 props

具有有限 props 的组件总是比具有大量 props 的组件性能更好。这始终是删除子组件中未使用的 props 的好方法。这里有一个清晰展示此示例的例子。

import React from 'react'
import { render } from 'react-dom'

function Avatar(props) {
  return (
    <div className="avatar-wrapper">
      <img className="avatar-img" alt="avatar" src={props.user.image} />
      <div className="avatar-name">{props.user.name}</div>
    </div>
  )
}

const user = {
  id: 1,
  name: 'Leanne Graham',
  image: 'https://i.picsum.photos/id/237/200/300.jpg',
  username: 'Bret',
  email: 'Sincere@april.biz',
  address: {
    street: 'Kulas Light',
    city: 'Gwenborough',
    zipcode: '92998-3874',
  },
}

render(<Avatar user={user} />, document.getElementById('root'))
Enter fullscreen mode Exit fullscreen mode

在这个例子中,<Avatar />组件只需要imagename属性。因此,每当其他属性(例如usernameemail或 )address更新时,<Avatar />组件都会重新渲染。从长远来看,这会导致性能问题。有很多方法可以删除属性,如何删除传递的属性完全取决于你。以下是我使用的方法。

import React from 'react'
import { render } from 'react-dom'

function Avatar(props) {
  return (
    <div className="avatar-wrapper">
      <img className="avatar-img" alt="avatar" src={props.image} />
      <div className="avatar-name">{props.name}</div>
    </div>
  )
}

const user = {
  id: 1,
  name: 'Leanne Graham',
  image: 'https://i.picsum.photos/id/237/200/300.jpg',
  username: 'Bret',
  email: 'Sincere@april.biz',
  address: {
    street: 'Kulas Light',
    city: 'Gwenborough',
    zipcode: '92998-3874',
  },
}

render(
  <Avatar name={user.name} image={user.image} />,
  document.getElementById('root')
)
Enter fullscreen mode Exit fullscreen mode

#2 对象和函数 props 的常见修复场景

React是沿着组件层级向下的单向数据流。因此,有时我们可能需要将函数传递给子组件。当我们将对象和函数式 props 传递给子组件时,我们需要执行额外的步骤,以避免在重新渲染期间重新创建对象和函数。这里有一个示例可以更好地解释这个概念。

import React from 'react'
import { render } from 'react-dom'

function Alert(props) {
  return (
    <div
      className="alert-wrapper"
      style={{ display: props.showAlert ? 'block' : 'none' }}
    >
      <div className="alert-close" onClick={props.handleCloseAlert}>
        X
      </div>
      <div className="alert-title">{props.alertData.title}</div>
      <div className="alert-description">{props.alertData.description}</div>
    </div>
  )
}

function App() {
  const [showAlert, setShowAlert] = React.useState(false)
  const [counter, setCounter] = React.useState(0)

  const alertData = {
    title: 'There was an error processing your request',
    description: 'Please try again...',
  }

  const handleShowAlert = () => {
    setShowAlert(true)
  }

  const handleCloseAlert = () => {
    setShowAlert(false)
  }

  const handleIncrementCounter = () => {
    setCounter(counter + 1)
  }

  return (
    <div>
      <button onClick={handleIncrementCounter}>counter: {counter}</button>
      <button onClick={handleShowAlert}>Show Me Alert</button>
      <Alert
        showAlert={showAlert}
        alertData={alertData}
        handleCloseAlert={handleCloseAlert}
      />
    </div>
  )
}

render(<App />, document.getElementById('root'))
Enter fullscreen mode Exit fullscreen mode

在这个例子中,我们创建了两个组件<App />其中一个是父组件,我们在其中定义了用于处理组件的状态逻辑。以下是一些分析器图像<Alert />可以帮助您了解具体情况。<App/><Alert />ReactDevTool

探查器应用程序-0

探查器警报-0

每当父组件状态更新时,子组件也会重新渲染,我们可以通过使用 、 或 方法来避免子组件的重新渲染memoPureComponent但这shouldComponentUpdate()无法帮助您比较对象和函数式的 props,因为每次都会为对象和函数创建一个新的引用。有几种方法可以防止重新创建它。

对于对象,您需要React.useMemo()像下面这样将对象包装在里面。

const alertData.= React.useMemo(() => {
    title: 'There was an error processing your request',
    description: 'Please try again...'
}, [])
Enter fullscreen mode Exit fullscreen mode

对于函数,您需要React.useCallback()像下面这样将函数包装在里面。

const handleCloseAlert = React.useCallback(() => {
    setShowAlert(false)
}, [])
Enter fullscreen mode Exit fullscreen mode

React.useMemo()的第二个参数React.useCallback()是依赖项数组。一个空的依赖项数组,其中包含我们不想重新计算的值React.useMemo()和记忆回调的特定依赖项React.useCallback()。在某些情况下,我们可能需要重新计算值和记忆回调,这取决于你。

这是上述示例的改进版本。

import React from 'react'
import { render } from 'react-dom'

function Alert(props) {
  return (
    <div
      className="alert-wrapper"
      style={{ display: props.showAlert ? 'block' : 'none' }}
    >
      <div className="alert-close" onClick={props.handleCloseAlert}>
        X
      </div>
      <div className="alert-title">{props.alertData.title}</div>
      <div className="alert-description">{props.alertData.description}</div>
    </div>
  )
}

function App() {
  const [showAlert, setShowAlert] = React.useState(false)
  const [counter, setCounter] = React.useState(0)

  const alertData = React.useMemo(
    () => ({
      title: 'There was an error processing your request',
      description: 'Please try again...',
    }),
    []
  )

  const handleShowAlert = React.useCallback(() => {
    setShowAlert(true)
  }, [])

  const handleCloseAlert = React.useCallback(() => {
    setShowAlert(false)
  }, [])

  const handleIncrementCounter = React.useCallback(() => {
    setCounter(counter + 1)
  }, [counter])

  return (
    <div>
      <button onClick={handleIncrementCounter}>counter: {counter}</button>
      <button onClick={handleShowAlert}>Show Me Alert</button>
      <Alert
        showAlert={showAlert}
        alertData={alertData}
        handleCloseAlert={handleCloseAlert}
      />
    </div>
  )
}

render(<App />, document.getElementById('root'))
Enter fullscreen mode Exit fullscreen mode

探查器应用程序-1
探查器警报-1

#3 React.memo 与 react-fast-compare

对每个组件都使用缓存React.memo()是有风险的,因为它会显式地缓存函数,这意味着它会将结果存储在内存中。如果对过多或过大的组件执行此操作,会导致更多的内存消耗。因此,在缓存大型组件时应格外小心。

通常,我们可以通过传递有限的 props 来避免重新渲染。如果您仍然想使用,React.memo()那么首先看看默认设置是否React.memo适合您。如果不行,则使用分析器来了解并识别组件中的瓶颈。毕竟,您已经确定可以通过在ReactDevTools之间进行深度相等性检查来解决这个问题prevPropsnextProps

让我们看看这个例子,

import React from 'react'
import { render } from 'react-dom'
import isEqual from 'react-fast-compare'

function Input(props) {
  return <input value={props.value} onChange={props.handleOnChange} />
}

const MemoizedInput = React.memo(Input, isEqual)

function App() {
  const [username, setUsername] = React.useState('')

  const handleOnChange = React.useCallback((e) => {
    setUsername(e.target.value)
  }, [])

  return <MemoizedInput value={username} handleOnChange={handleOnChange} />
}

render(<App />, document.getElementById('root'))
Enter fullscreen mode Exit fullscreen mode

感谢阅读。希望你喜欢这篇文章,欢迎点赞、评论或分享给你的朋友。

文章来源:https://dev.to/sagar/things-should-be-considered-while-writing-your-react-components-3n4a
PREV
5分钟内使用Flask构建聊天机器人
NEXT
JavaScript——深入了解“this”关键字