Различные способы добавить ключ к элементу JSX в цикле в React - PullRequest
0 голосов
/ 06 сентября 2018

Я работаю над реакцией уже больше года. Я в основном играл с итерацией массива, используя .map, .forEach, .filter или используя Object.keys и Object.values, если это объект.

Но каковы разные способы добавления уникального ключа в элемент jsx. Вот то, к чему я привык до сих пор

Использование уникального идентификатора из данных в качестве ключа к ключевому слову:

const data= [{"id": "01", "name": "abc"}, {"id": "02", "name": "xyz"}];

render(){
  const items = data.map(item => {
    return <span key={item.id}>{item.name}</span>;
  }
  return(
     <div>
        {items}
     </div>
  )
}

Использование индекса в качестве ключа для ключевого слова:

const data= [{"id": "01", "name": "abc"}, {"id": "02", "name": "xyz"}];

render(){
  const items = data.map((item, i) => {
    let keyValue = i+1;
    return <span key={keyValue}>{item.name}</span>;
  }
  return(
     <div>
        {items}
     </div>
  )
}

Есть ли другие способы добавить уникальный ключ к элементу jsx, кроме того, что я упомянул выше, и какой наиболее эффективен и рекомендован?

Ответы [ 4 ]

0 голосов
/ 19 сентября 2018

Вы можете использовать Date.now () с index , ваш код будет как пример

const data= [{"id": "01", "name": "abc"}, {"id": "02", "name": "xyz"}];

render(){
  const items = data.map((item, i) => {
    let keyValue = Date.now()+i;
    return <span key={keyValue}>{item.name}</span>;
  }
  return(
     <div>
        {items}
     </div>
  )
}
0 голосов
/ 14 сентября 2018

Лучший способ выбрать ключ - использовать строку, которая однозначно идентифицирует элемент списка среди его братьев и сестер. Чаще всего вы используете идентификаторы из ваших данных в качестве ключей:

const todoItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
);

Если у вас нет стабильных идентификаторов для визуализированных элементов, вы можете использовать индекс элемента в качестве ключа в качестве крайней меры:

const todoItems = todos.map((todo, index) =>
  // Only do this if items have no stable IDs
  <li key={index}>
    {todo.text}
  </li>
);

Также обратите внимание:

Ключи, используемые в массивах, должны быть уникальными среди их братьев и сестер. Однако они не должны быть уникальными во всем мире.

Однако реальный ответ на ваш вопрос живет здесь: https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318

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

Вы можете добавить их непосредственно в объект в массиве

const todos = [
  { 
    id: uuid(),
    text: 'foo',
  }
]

и повторять так:

const todoItems = todos.map(({id, text}) =>
  <li key={id}>
    {text}
  </li>
);
0 голосов
/ 15 сентября 2018

Прежде всего, избегайте использования случайных ключей .

Существует множество способов написания ключей, и некоторые из них будут работать лучше, чем другие.

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

https://reactjs.org/docs/reconciliation.html

tl; dr Вводит эвристику для сравнения деревьев Virtual DOM, чтобы сделать это сравнение O (n) с n узлами этого дерева VDOM. Эту эвристику можно разделить на следующие пункты:

  • Компоненты другого типа создадут новое дерево : Это означает, что при сравнении старого дерева с новым, если примиритель обнаружит, что узел действительно изменил свой тип (например, <Button /> на <NotButton />), приведет к тому, что наша кнопка также будет размонтирована с ее дочерними элементами, а NotButton - с ее дочерними элементами.
  • Мы можем подсказать Реагировать на то, как экземпляры сохраняются в VDOM, избегая их повторного создания. Эти подсказки предоставляются нами с ключами. : После принятия решения о том, следует ли сохранять экземпляр в узле (поскольку его тип остается прежним), примиритель будет выполнять итерацию по дочерним узлам этого узла, чтобы сравнить их.

Предположим, теперь у нас есть это:

<div>
  <Button title="One" />
  <Button title="Two" />
</div>

И мы хотели бы добавить кнопку в DOM на следующем рендере, скажем,

<div>
  <Button title="Zero" />
  <Button title="One" />
  <Button title="Two" />
</div>

Алгоритм будет выглядеть следующим образом:

  • Сравнивает <divs> в обоих VDOM. Поскольку они имеют одинаковый тип, нам не нужно заново создавать новое дерево. Реквизиты те же, поэтому на данный момент нет изменений, которые можно применить к DOM.
  • Кнопка One сравнивается с Zero. Reconciler обнаруживает, что здесь произошла смена реквизита, затем обновляет DOM с таким названием.
  • Кнопка Two сравнивается с One. Reconcilier также обнаруживает изменение реквизита и использует DOM для записи этого изменения.
  • Обнаруживает, что новый Button добавлен как последний дочерний элемент, поэтому создает новый экземпляр Button в VDOM и записывает это изменение в DOM.

Обратите внимание, что они выполняют много операций в DOM, поскольку сравнивают компоненты по их индексу.

Теперь мы можем исправить это поведение, сообщив нашему посреднику, что эти экземпляры следует использовать повторно. Теперь, давайте иметь это:

<div>
  <Button title="One" key="One" />
  <Button title="Two" key="Two" />
</div>

И мы хотели бы добавить кнопку в DOM на следующем рендере, скажем

<div>
  <Button title="Zero" key="Zero" />
  <Button title="One" key="One" />
  <Button title="Two" key"Two" />
</div>

Алгоритм будет выглядеть следующим образом:

  • Сравнивает <divs> в обоих VDOM. Поскольку они имеют одинаковый тип, нам не нужно заново создавать новое дерево. Реквизиты те же, поэтому на данный момент нет изменений, которые можно применить к DOM.
  • Берет первого ребенка из детей. «Это Button», говорит примиритель. «И есть ключ» («One»). Затем ищет детей с тем же ключом в новом списке детей. «О, я столкнулся с этим! но примиритель понимает, что нет никаких изменений в его реквизитах . Тогда никакие операции DOM для этого не понадобятся.
  • Тот же сценарий происходит со вторым Button, он будет сравниваться на keys вместо index. Понимает, что это тот же экземпляр, и реквизиты не были изменены, поэтому React решает не применять изменения в DOM.
  • Для Button с ключом 'Zero', поскольку не существует дочернего элемента с таким же ключом , он понимает, что экземпляр должен быть создан в VDOM, и это изменение должно быть записано в DOM.

Таким образом, использование ключей с предсказуемым содержимым помогает примирителю выполнять меньше операций с DOM. Здоровые ключи - это те, которые могут быть выведены из отображаемого объекта, например, name, или id, или даже url, если мы преобразуем urls в <imgs />.

А как насчет key=index? Не будет иметь никакого эффекта, так как по умолчанию, компилятор сравнивает по позиции, то есть по индексу.

Эти ключи должны быть глобально уникальными? Не обязательно. Они должны быть уникальными среди братьев и сестер, поэтому примиритель может различать их во время итерации по дочерним узлам.

А как насчет случайных ключей?Этого следует избегать любой ценой.Если ключ изменяется при каждом рендеринге, это будет приводить к тому, что React будет уничтожать и создавать экземпляры в VDOM (и, следовательно, делать дополнительные записи в DOM), поскольку компонент с ключом не найден среди новых дочерних элементов, но новыйс тем же типом.

Если вывод рендеринга похож на

<div>
  <Button key={randomGenerator()} />
</div>

Затем каждый раз выполняется render (например, из-за изменения реквизита / состояния или даже если его родительПосле повторного рендеринга и shouldComponentUpdate возвращает true), будет сгенерирован новый ключ randomGenerator().Это будет выглядеть так:

'Эй!Я нашел Button с ключом F67BMkd==, но ни один не был найден в следующем.Я удалю это.'Ой!Я встретил Button с ключом SHDSA++5!Давайте создадим новый ».

Всякий раз, когда примиритель говорит, что экземпляр должен быть удален и размонтирован, его внутреннее состояние будет потеряно;даже если мы установим его снова.Экземпляр в VDOM не будет сохранен в этом случае.

Button был таким же, но примиритель сделал беспорядок в DOM.

Надеюсь, это поможет.

0 голосов
/ 14 сентября 2018

md5 sha1 или даже sha256 по содержанию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...