📖 История «Stop unnecessary re-rendering component in React !!!»

когда-то давно…

💎 Генерация компонента класса

🚩 Чистый компонент()

Сравниваем новый и старый props/state, если между ними есть разница, компонент рендерится

сравнить?? но как их сравнить????

<< случай рендеринга в React >>

  1. изменение состояния
  2. родительский компонент рендерится
  3. изменения реквизита
  4. функция shouldcomponentUpdate возвращает true (об этом я расскажу позже)
  5. forceUpdate

для номеров 1 и 2, React решает, нужно ли рендерить через неглубокое сравнение.

Что такое неглубокое сравнение?

Для начала нам нужно понять, что такое ссылка
▼ с этого сайта

  1. Передача по ссылке (неглубокое копирование)
    Если вы наливаете кофе в скопированную чашку, то оригинальная чашка тоже наполнится им (потому что оба данных находятся в одном пространстве выделения памяти)

  2. передача по значению (глубокое копирование)
    Если вы наливаете кофе в скопированную чашку, оригинальная чашка остается пустой

в Javascript примитивные типы данных (String, Number, Bigint, Boolean, Undefined, Symbol) передаются по значению, а Object, Array — по ссылке.

Честно говоря, сравнение с примитивным типом данных не так сложно, но нам нужно позаботиться о сравнении с Object.

случай ссылки на объект такой же

import shallowCompare from 'react-addons-shallow-compare';

const a = { country: "poland", country2: "japan" }
const b = a

console.log(shallowEqual(a, b))
// true
Вход в полноэкранный режим Выйти из полноэкранного режима

случай ссылки на объект отличается

  1. не вложенный объект
import shallowCompare from 'react-addons-shallow-compare';

const a = { country: "poland", country2: "japan" }
const b = { country: "poland", country2: "japan" }

console.log(shallowEqual(a, b))
// true
Войти в полноэкранный режим Выйти из полноэкранного режима
  1. вложенный объект
import shallowCompare from 'react-addons-shallow-compare';

const a = {
  country: "poland",
  coountry2: {
    city1: "tokyo",
    city2: "osaka"
  }
}

const b = {
  country: "poland", // country is primitive type, scalar data is the same -> true
  country2: { // country2 is object, so reference is different -> false
    city1: "tokyo",
    city2: "osaka"
  }
}

console.log(shallowEqual(a, b))
// ⭐ false
Войти в полноэкранный режим Выход из полноэкранного режима

🚩 shouldComponentUpdate()

👦 так что все компоненты являются чистыми компонентами, не так ли?
👩💻 нет, потому что стоимость сравнения старого и нового состояния/процессов высока
👦 что мне тогда делать?
👩💻 просто решите сравнение состояния самостоятельно через «shouldComponentUpdate()»

на самом деле PureComponent — это как компонент, который реализуется кем-то (будь то кто-то в компании facebook) через shouldComponentUpdate()

// something like that
class PureComponent extends React.Component {
    shouldComponentUpdate(nextProps, nextState) {
        return !(shallowEqual(this.props, nextProps) && shallowEqual(this.state, nextState));
    }
    
}
Вход в полноэкранный режим Выход из полноэкранного режима

💎 Поколение функциональных компонентов

2022 мы находимся в этом поколении

🚩 React.memo

это как PureComponent() + shouldComponentUpdate()

// if new props changes, this component will be rendered
const Button = React.memo(props => {
    return <div>{props.value}</div>
})
Вход в полноэкранный режим Выход из полноэкранного режима
// if you put second argument, it is like shouldComponentUpdate()
const Button = React.memo(
    props => {
        return <div>{props.value}</div>
    },
    (nextProps, prevProps) => {
        return nextProps.value === prevProps.value
    }
)
Войти в полноэкранный режим Выход из полноэкранного режима

🚩 useMemo

👦 что такое useMemo? это то же самое, что и React.memo?
👩💻 нет, хотя и похоже. React.memo добавлен в React версии16.6, а затем React hook добавлен в версии 16.8, useMemo также.
👦 ага
👩💻 useMemo рендерит только при изменении реквизита, потому что запоминает результат вычислений.

// when only "products props" changes, this component renders
const Component: React.FC = ({ products }) => {
    const soldoutProducts = React.useMemo(() => products.filter(x => x.isSoldout === true), [products])
}
Вход в полноэкранный режим Выйти из полноэкранного режима

🚩 useCallback

Когда родительский компонент передает реквизит функции дочернему компоненту, создается новая функция (на самом деле функция — это просто один из объектов).
Благодаря этому дочерний компонент распознает, что новая функция отличается от старой, после чего с грустью перерисовывает ее.

↓ разговор между детским/родительским компонентом

👨 Parent「re-renderiiingggg!!! И теперь я воссоздал функцию, которая у меня есть !!!」
👼 Ребенок「 Мама!!! Дай мне свою функцию в качестве реквизита!!!」
👨 Родитель「ok Я отдаю тебе свою функцию! 」
👼 Child「 Well now I need to confirm this object’s memory address is the same same object that I got before ….. Если адрес другой, то я также перерисовываю!!!」

чтобы предотвратить этот ненужный повторный рендеринг, нужно использовать useCallback

Оцените статью
Procodings.ru
Добавить комментарий