Оптимизация производительности React
3 совета по оптимизации производительности React

1. Избегайте передачи ненужных реквизитов дочерним компонентам.
Компонент с ограниченным количеством реквизитов всегда выполняется лучше, чем компонент, имеющий много реквизитов. Это всегда хороший способ отбросить реквизиты, которые не используются внутри дочерних компонентов. Вот пример, который показывает ясную картину этого.
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/30.jpg',
username: 'Bret',
email: 'Sincere@april.biz',
address: {
street: 'Kulas Light',
city: 'Gwenborough',
zipcode: '92998-3874',
},
}
render(<Avatar user={user} />, document.getElementById('root'))
В этом примере компоненту <Avatar /> нужны только реквизиты изображения и имени. Поэтому, когда обновляются другие реквизиты, такие как имя пользователя, адрес электронной почты или адрес, компонент <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/30.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')
)
2. Общие сценарии исправления для объектов и функций реквизита
React - это односторонний поток данных по иерархии компонентов. Поэтому иногда нам может понадобиться передать функцию дочернему компоненту. Когда мы передаем объектные и функциональные реквизиты дочернему компоненту, мы должны сделать еще один шаг, чтобы избежать повторного создания объектов и функций во время повторного рендеринга. Вот пример, который лучше объяснит эту концепцию.
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'))
В этом примере мы создали два компонента <App /> и <Alert />. <App /> - это родительский компонент, в котором мы определили логику с состоянием для обработки компонента <Alert />. Вот некоторые изображения профилировщика ReactDevTool для понимания того, что происходит.
Всякий раз, когда состояние родительского компонента обновляется, потомки также перерисовываются, и мы можем избежать повторного рендеринга дочернего компонента, используя метод memo, PureComponent или shouldComponentUpdate (). Но это не поможет вам в сравнении объектов и функциональных реквизитов, потому что каждый раз будет создаваться новая ссылка для объекта и функции. Есть несколько способов предотвратить его повторное создание.
Для объекта вам нужно обернуть объект внутри React.useMemo (), как показано ниже.
title: 'There was an error processing your request',
description: 'Please try again...'
}, [])
Для функций вам нужно обернуть функцию внутри React.useCallback (), как показано ниже.
setShowAlert(false)
}, [])
Второй аргумент для 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'))
3. React.memo с реагировать-быстро сравнить
Использование React.memo () для каждого компонента рискованно, поскольку он явно кэширует функцию, а это означает, что он сохраняет результат в памяти. Если вы сделаете это со слишком большим количеством компонентов, это приведет к большему потреблению памяти. Вот почему вы должны быть осторожны при запоминании больших компонентов.
В основном, мы можем избежать повторного рендеринга, передавая ограниченное количество реквизитов. если вы все еще хотите использовать React.memo (), то сначала посмотрите, будет ли работать React.memo по умолчанию. Если это не так, то определите место в вашем компоненте с помощью профилировщика ReactDevTools. В конце концов, вы определили, что эту проблему можно решить с помощью глубоких проверок равенства между prevProps и nextProps.
Давайте посмотрим на примере,
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'))
«Необычные мыслители повторно используют то, от чего отказываются обычные мыслители».
- Дж. Р. Д. Тата
Спасибо за чтение.
Похожие

Lifehacks
Dec 27 2023Как программировать с помощью ChatGPT?

Lifehacks
Jun 8 2020Стек на C++

Lifehacks
Jul 31 202310 мощных скриптов автоматизации Python

Lifehacks
Aug 29 2020Лучшие инструменты разработки программного обеспечения для максимальной производительности программного проекта
Получай полезные статьи, новости и темы ежедневно