{"componentChunkName":"component---src-templates-docs-js","path":"/docs/reconciliation.html","result":{"data":{"markdownRemark":{"html":"<p>React предоставляет декларативный API, который позволяет не беспокоиться о том, что именно изменяется при каждом обновлении. Благодаря этому, писать приложения становится намного проще, но может быть неочевидно как именно это реализовано внутри React. В этой статье объясняются решения, принятые нами для алгоритма сравнения в React, которые делают обновления компонента предсказуемыми, и в то же время достаточно быстрыми для высокопроизводительных приложений.</p>\n<h2 id=\"motivation\"><a href=\"#motivation\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Мотивация </h2>\n<p>При работе с React вы можете понимать <code class=\"gatsby-code-text\">render()</code> как функцию, которая создаёт дерево React-элементов в какой-то момент времени. При последующем обновлении состояния или пропсов функция <code class=\"gatsby-code-text\">render()</code> вернёт новое дерево React-элементов. Теперь React должен понять, как эффективно обновить UI, чтобы он совпадал с новейшим из деревьев.</p>\n<p>Существует несколько общих решений алгоритмической проблемы трансформации одного дерева в другое за минимальное количество операций. Тем не менее, <a href=\"http://grfia.dlsi.ua.es/ml/algorithms/references/editsurvey_bille.pdf\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">передовые алгоритмы</a> имеют сложность порядка O(n<sup>3</sup>), где n — это число элементов в дереве.</p>\n<p>Если бы мы использовали это в React, отображение 1000 элементов потребовало бы порядка миллиарда сравнений. Это слишком дорого. Взамен, React реализует эвристический алгоритм O(n), который основывается на двух предположениях:</p>\n<ol>\n<li>Два элемента с разными типами произведут разные деревья.</li>\n<li>Разработчик может указать, какие дочерние элементы могут оставаться стабильными между разными рендерами с помощью пропа <code class=\"gatsby-code-text\">key</code>.</li>\n</ol>\n<p>На практике эти предположения верны почти для всех случаев.</p>\n<h2 id=\"the-diffing-algorithm\"><a href=\"#the-diffing-algorithm\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Алгоритм сравнения </h2>\n<p>При сравнении двух деревьев первым делом React сравнивает два корневых элемента. Поведение различается в зависимости от типов корневых элементов.</p>\n<h3 id=\"elements-of-different-types\"><a href=\"#elements-of-different-types\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Элементы различных типов </h3>\n<p>Всякий раз, когда корневые элементы имеют различные типы, React уничтожает старое дерево и строит новое с нуля. Переходы от <code class=\"gatsby-code-text\">&lt;a&gt;</code> к <code class=\"gatsby-code-text\">&lt;img&gt;</code>, или от <code class=\"gatsby-code-text\">&lt;Article&gt;</code> к <code class=\"gatsby-code-text\">&lt;Comment&gt;</code>, или от <code class=\"gatsby-code-text\">&lt;Button&gt;</code> к <code class=\"gatsby-code-text\">&lt;div&gt;</code> приведут к полному перестроению.</p>\n<p>При уничтожении дерева старые DOM-узлы удаляются. Экземпляры компонента получают <code class=\"gatsby-code-text\">componentWillUnmount()</code>. При построении нового дерева, новые DOM-узлы вставляются в DOM. Экземпляры компонента получают <code class=\"gatsby-code-text\">componentWillMount()</code>, а затем <code class=\"gatsby-code-text\">componentDidMount()</code>. Любое состояние, связанное со старым деревом, теряется.</p>\n<p>Любые компоненты, лежащие ниже корневого, также размонтируются, а их состояние уничтожится. Например, это произойдёт при таком сравнении: </p>\n<div class=\"gatsby-highlight\" data-language=\"html\"><pre class=\"gatsby-code-html\"><code class=\"gatsby-code-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>Counter</span> <span class=\"token punctuation\">/></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span>\n\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>span</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>Counter</span> <span class=\"token punctuation\">/></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>span</span><span class=\"token punctuation\">></span></span></code></pre></div>\n<p>При этом старый <code class=\"gatsby-code-text\">Counter</code> уничтожится, а новый — смонтируется.</p>\n<h3 id=\"dom-elements-of-the-same-type\"><a href=\"#dom-elements-of-the-same-type\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>DOM-элементы одного типа </h3>\n<p>При сравнении двух React DOM-элементов одного типа, React смотрит на атрибуты обоих, сохраняет лежащий в основе этих элементов DOM-узел и обновляет только изменённые атрибуты. Например:</p>\n<div class=\"gatsby-highlight\" data-language=\"html\"><pre class=\"gatsby-code-html\"><code class=\"gatsby-code-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span> <span class=\"token attr-name\">className</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>before<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">title</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>stuff<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span>\n\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span> <span class=\"token attr-name\">className</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>after<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">title</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>stuff<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span></code></pre></div>\n<p>Сравнивая эти элементы, React знает, что нужно модифицировать только <code class=\"gatsby-code-text\">className</code> у лежащего в основе DOM-узла.</p>\n<p>Обновляя <code class=\"gatsby-code-text\">style</code>, React также знает, что нужно обновлять только изменившиеся свойства. Например: </p>\n<div class=\"gatsby-highlight\" data-language=\"html\"><pre class=\"gatsby-code-html\"><code class=\"gatsby-code-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span> <span class=\"token attr-name\">style</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span>{{color:</span> <span class=\"token attr-name\">'red',</span> <span class=\"token attr-name\"><span class=\"token namespace\">fontWeight:</span></span> <span class=\"token attr-name\">'bold'}}</span> <span class=\"token punctuation\">/></span></span>\n\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span> <span class=\"token attr-name\">style</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span>{{color:</span> <span class=\"token attr-name\">'green',</span> <span class=\"token attr-name\"><span class=\"token namespace\">fontWeight:</span></span> <span class=\"token attr-name\">'bold'}}</span> <span class=\"token punctuation\">/></span></span></code></pre></div>\n<p>При конвертации между этими элементами, React знает, что нужно модифицировать только стиль <code class=\"gatsby-code-text\">color</code>, а <code class=\"gatsby-code-text\">fontWeight</code> сохранить.</p>\n<p>После обработки DOM-узла React рекурсивно проходится по дочерним элементам.</p>\n<h3 id=\"component-elements-of-the-same-type\"><a href=\"#component-elements-of-the-same-type\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Компоненты одного типа </h3>\n<p>Когда компонент обновляется, его экземпляр остаётся прежним, поэтому его состояние сохраняется между рендерами. React обновляет пропсы базового экземпляра компонента для соответствия новому элементу и вызывает <code class=\"gatsby-code-text\">componentWillReceiveProps()</code> и <code class=\"gatsby-code-text\">componentWillUpdate()</code> на базовом экземпляре.</p>\n<p>Далее вызывается метод <code class=\"gatsby-code-text\">render()</code> и алгоритм сравнения рекурсивно обходит предыдущий и новый результаты.</p>\n<h3 id=\"recursing-on-children\"><a href=\"#recursing-on-children\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Рекурсия по дочерним элементам </h3>\n<p>По умолчанию при рекурсивном обходе дочерних элементов DOM-узла React проходит по обоим спискам потомков одновременно и создаёт мутацию, когда находит отличие.</p>\n<p>Например, при добавлении элемента в конец дочерних элементов, преобразование между этими деревьями работает отлично: </p>\n<div class=\"gatsby-highlight\" data-language=\"html\"><pre class=\"gatsby-code-html\"><code class=\"gatsby-code-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span><span class=\"token punctuation\">></span></span>первый<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span><span class=\"token punctuation\">></span></span>второй<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>ul</span><span class=\"token punctuation\">></span></span>\n\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span><span class=\"token punctuation\">></span></span>первый<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span><span class=\"token punctuation\">></span></span>второй<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span><span class=\"token punctuation\">></span></span>третий<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>ul</span><span class=\"token punctuation\">></span></span></code></pre></div>\n<p>React сравнит два дерева <code class=\"gatsby-code-text\">&lt;li&gt;первый&lt;/li&gt;</code>, сравнит два дерева <code class=\"gatsby-code-text\">&lt;li&gt;второй&lt;/li&gt;</code>, а затем вставит дерево <code class=\"gatsby-code-text\">&lt;li&gt;третий&lt;/li&gt;</code>.</p>\n<p>Если попробовать реализовать это наивно, вставив элемент в начало, то пострадает производительность. Например, преобразование между этими деревьями работает плохо: </p>\n<div class=\"gatsby-highlight\" data-language=\"html\"><pre class=\"gatsby-code-html\"><code class=\"gatsby-code-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span><span class=\"token punctuation\">></span></span>Санкт-Петербург<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span><span class=\"token punctuation\">></span></span>Москва<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>ul</span><span class=\"token punctuation\">></span></span>\n\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span><span class=\"token punctuation\">></span></span>Ростов-на-Дону<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span><span class=\"token punctuation\">></span></span>Санкт-Петербург<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span><span class=\"token punctuation\">></span></span>Москва<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>ul</span><span class=\"token punctuation\">></span></span></code></pre></div>\n<p>React будет мутировать каждого потомка, вместо того чтобы оставить <code class=\"gatsby-code-text\">&lt;li&gt;Санкт-Петербург&lt;/li&gt;</code>  и <code class=\"gatsby-code-text\">&lt;li&gt;Москва&lt;/li&gt;</code> нетронутыми. Эта неэффективность может стать проблемой.</p>\n<h3 id=\"keys\"><a href=\"#keys\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Ключи </h3>\n<p>Для решения этой проблемы React поддерживает атрибут <code class=\"gatsby-code-text\">key</code>. Когда у дочерних элементов есть ключи, React использует их, чтобы сопоставить потомков исходного дерева с потомками последующего дерева. Например, если добавить <code class=\"gatsby-code-text\">key</code> к неэффективному примеру выше, преобразование дерева станет эффективным:</p>\n<div class=\"gatsby-highlight\" data-language=\"html\"><pre class=\"gatsby-code-html\"><code class=\"gatsby-code-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span> <span class=\"token attr-name\">key</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>2015<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>Санкт-Петербург<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span> <span class=\"token attr-name\">key</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>2016<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>Москва<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>ul</span><span class=\"token punctuation\">></span></span>\n\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span> <span class=\"token attr-name\">key</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>2014<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>Ростов-на-Дону<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span> <span class=\"token attr-name\">key</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>2015<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>Санкт-Петербург<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span> <span class=\"token attr-name\">key</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>2016<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>Москва<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>ul</span><span class=\"token punctuation\">></span></span></code></pre></div>\n<p>Теперь React знает, что элемент с ключом <code class=\"gatsby-code-text\">&#39;2014&#39;</code> — новый, а элементы с ключами <code class=\"gatsby-code-text\">&#39;2015&#39;</code> и <code class=\"gatsby-code-text\">&#39;2016&#39;</code> только что переместились.</p>\n<p>На практике найти ключ обычно несложно. Элемент, который вы хотите отобразить, уже может иметь уникальный идентификатор, и ключ может быть взят из ваших данных:</p>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span> <span class=\"token attr-name\">key</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>item<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>item<span class=\"token punctuation\">.</span>name<span class=\"token punctuation\">}</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span></code></pre></div>\n<p>Когда уникальное значение отсутствует, вы можете добавить новое свойство идентификатора в вашу модель или прохешировать данные, чтобы сгенерировать ключ. Ключ должен быть уникальным только среди его соседей, а не глобально.</p>\n<p>В крайнем случае вы можете передать индекс элемента массива в качестве ключа. Это работает хорошо в случае, если элементы никогда не меняют порядок. Перестановки элементов вызывают замедление.</p>\n<p>При использовании ключей перестановки так же могут вызывать проблемы с состоянием компонента. Экземпляры компонента обновляются и повторно используются на основе их ключей. Перемещение элемента изменяет его, если ключ является индексом. В результате состояние компонента для таких вещей, как неуправляемые <code class=\"gatsby-code-text\">&lt;input&gt;</code>, может смешаться и обновиться неожиданным образом.</p>\n<p>На CodePen <a href=\"/redirect-to-codepen/reconciliation/index-used-as-key\" target=\"_blank\" rel=\"noreferrer\">есть примеры проблем, которые могут быть вызваны использованием индексов в качестве ключей</a>, а также есть <a href=\"/redirect-to-codepen/reconciliation/no-index-used-as-key\" target=\"_blank\" rel=\"noreferrer\">обновлённая версия того же примера, которая показывает как решаются проблемы с перестановкой, сортировкой и вставкой элементов в начало, если не использовать индексы как ключи</a>.</p>\n<h2 id=\"tradeoffs\"><a href=\"#tradeoffs\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Компромиссы </h2>\n<p>Важно помнить, что алгоритм согласования — это деталь реализации. React может повторно рендерить всё приложение на каждое действие, конечный результат будет тем же. Для ясности, повторный рендер в этом контексте означает вызов функции <code class=\"gatsby-code-text\">render</code> для всех компонентов, но это не означает, что React размонтирует и смонтирует их заново. Он применит различия только следуя правилам, которые были обозначены в предыдущих разделах.</p>\n<p>Мы регулярно совершенствуем эвристику, чтобы ускорить часто встречающиеся варианты использования. В текущей реализации вы можете выразить факт того, что поддерево сдвинулось среди его соседей, но вы не можете сказать, что оно сдвинулось куда-то в другое место. Алгоритм повторно отрендерит всё поддерево.</p>\n<p>React полагается на эвристику, следовательно, если предположения, на которых она основана, не соблюдены, пострадает производительность. </p>\n<ol>\n<li>Алгоритм не будет пытаться сопоставить поддеревья компонентов разных типов. Если вы заметите за собой, что пытаетесь чередовать компоненты разных типов с очень схожим выводом, то желательно сделать их компонентами одного типа. На практике мы не выявили с этим проблем.</li>\n<li>Ключи должны быть стабильными, предсказуемыми и уникальными. Нестабильные ключи (например, произведённые с помощью <code class=\"gatsby-code-text\">Math.random()</code>) вызовут необязательное пересоздание многих экземпляров компонента и DOM-узлов, что может вызывать ухудшение производительности и потерю состояния у дочерних компонентов.</li>\n</ol>","frontmatter":{"title":"Согласование","next":null,"prev":null},"fields":{"path":"content/docs/reconciliation.md","slug":"docs/reconciliation.html"}}},"pageContext":{"slug":"docs/reconciliation.html"}},"staticQueryHashes":[]}