Почему key в React нужен только в перечислениях?

142
17 августа 2021, 05:50

Была поставлена задача реализовать свою JSX factory. Из документации React мы знаем, что JSX транспилируется в вызов функции React.createElement(type,props,child), где child выражено rest параметром (передает через запятую массив потомков). Но каким образом сравниваются текущее и новое древо? Ведь это абсолютно обособленные объекты.

import React, { Component } from 'react';
class App extends Component {
  render() {
    return (
      <div>
        <p>It's</p>
        <p>OK</p>
      </div>
    );
  }
}
export default App;

Кроме того, что является критерием невозможности частичного рендеринга без поля key в перечислении? Мы же можем поставить два блока p подряд и ничего страшного не произойдет...

Answer 1

При получении child происходит "уплощение массива" - для избавления от включений map(), которые возвращают массив. Далее сравнение элементов древ можно осуществить следующим алгоритмом:

  1. Мы сравниваем key и type текущих сопоставляемых элементов
  2. Если совпали, идем к родителям

    • Если совпали, повторяем действие
    • Если одного из родителей не оказалось, элементы не равны
    • Если не оказалось сразу двух родителей, сравнение истинно

Реализация данного алгоритма в псевдо-коде:

bool Element::equals(
    const Element* a,
    const Element* b,
    bool recursive=true
) {
    if (a->key!=b->key) {
        return false;
    } else if (a->type!=b->type) {
        return false;
    } else if (recursive) {
        const Element* parent1 = a;
        const Element* parent2 = b;
        while(true) {
            parent1 = parent1->parent;
            parent2 = parent2->parent;
            if (parent1==nullptr&&parent2==nullptr) {
                return true;
            } else if (parent1==nullptr&&parent2!=nullptr) {
                return false;
            } else if (parent1!=nullptr&&parent2==nullptr) {
                return false;
            } else if (!equals(parent1, parent2, false)) {
                return false;
            } else {
                continue;
            }
        }
    } else {
        return true;
    }
}

Критерием невозможности частичного рендеринга является наличие трех и более (в строковом представлении древа потомков) эквивалентных элементов подряд, так как при попытке определить изменения будут удалены последние, а не изменившиеся.

Более подробно об этом явлении можно прочитать в этом репозитории.

READ ALSO
Как отдельно определить стили для разных ориентаций печатаемых страниц?

Как отдельно определить стили для разных ориентаций печатаемых страниц?

Когда пользователь желает распечатать страницу, в зависимости от того какую ориентацию, в открывшемся окне, он выберет (портретная/альбомная),...

121
Правильное удаление клика с элементов

Правильное удаление клика с элементов

Хотелось бы, чтобы при нажатии на кнопку прошлый клик с переменной 'hi' удалялсяНо почему-то этого не происходит

111
Почему слайдер не работает?

Почему слайдер не работает?

Есть слайдер, который должен перелистывать картинки

90
react-redux Виджет комментариев

react-redux Виджет комментариев

Я обучаюсь сейчас reduxЗадача стоит в том, чтобы переписать виджет комментариев с одного react на redux

175