{"componentChunkName":"component---src-templates-docs-js","path":"/docs/concurrent-mode-suspense.html","result":{"data":{"markdownRemark":{"html":"<style>\n.scary > blockquote {\n  background-color: rgba(237, 51, 21, 0.2);\n  border-left-color: #ed3315;\n}\n</style>\n<div class=\"scary\">\n<blockquote>\n<p>Внимание:</p>\n<p>На странице описаны <strong>экспериментальные функции, <a href=\"/docs/concurrent-mode-adoption.html\">которых ещё нет</a> в стабильной версии</strong>. Не используйте экспериментальные сборки React в продакшн приложениях. Эти функции могут значительно измениться без предупреждения перед тем, как попасть в React.</p>\n<p>Эта документация нацелена на ранних пользователей и интересующихся. Если вы новичок в React, не беспокойтесь об этих возможностях — вам не нужно изучать их прямо сейчас. Например, если вы ищете актуальное на сегодня руководство по получению данных, прочитайте <a href=\"https://www.robinwieruch.de/react-hooks-fetch-data/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">эту статью</a>.</p>\n</blockquote>\n</div>\n<p>В React 16.6 добавлен компонент <code class=\"gatsby-code-text\">&lt;Suspense&gt;</code>, который позволяет «ждать» загрузки кода и декларативно показывать состояние загрузки (например, спиннер), пока мы ожидаем:</p>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"token keyword\">const</span> ProfilePage <span class=\"token operator\">=</span> React<span class=\"token punctuation\">.</span><span class=\"token function\">lazy</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">import</span><span class=\"token punctuation\">(</span><span class=\"token string\">'./ProfilePage'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// Ленивая загрузка</span>\n\n<span class=\"token comment\">// Показать спиннер, во время загрузки профиля</span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Suspense</span></span> <span class=\"token attr-name\">fallback</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Spinner</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n  </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ProfilePage</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\">\n</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Suspense</span></span><span class=\"token punctuation\">></span></span></code></pre></div>\n<p>Задержка при получении данных — это новая возможность, которая позволяет использовать <code class=\"gatsby-code-text\">&lt;Suspense&gt;</code> и <strong>декларативно «ждать» чего-либо ещё, включая данные.</strong> Эта страница описывает получение данных, однако это применимо к изображениям, скриптам и другим асинхронным действиям.</p>\n<ul>\n<li>\n<p><a href=\"#what-is-suspense-exactly\">Что такое задержка?</a></p>\n<ul>\n<li><a href=\"#what-suspense-is-not\">Чем задержка не является</a></li>\n<li><a href=\"#what-suspense-lets-you-do\">Что позволяет делать задержка</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"#using-suspense-in-practice\">Использование задержки на практике</a></p>\n<ul>\n<li><a href=\"#what-if-i-dont-use-relay\">Что если я не использую Relay?</a></li>\n<li><a href=\"#for-library-authors\">Для авторов библиотек</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"#traditional-approaches-vs-suspense\">Классические подходы против задержки</a></p>\n<ul>\n<li><a href=\"#approach-1-fetch-on-render-not-using-suspense\">Подход 1: «Получаем после рендера»‎ (задержка не используется)</a></li>\n<li><a href=\"#approach-2-fetch-then-render-not-using-suspense\">Подход 2: «Получаем потом рендерим»‎ (задержка не используется)</a></li>\n<li><a href=\"#approach-3-render-as-you-fetch-using-suspense\">Подход 3: «Рендерим во время получения данных»‎ (используем задержку)</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"#start-fetching-early\">Начинаем получать данные рано</a></p>\n<ul>\n<li><a href=\"#were-still-figuring-this-out\">Мы все ещё в этом разбираемся</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"#suspense-and-race-conditions\">Задержка и состояние гонки</a></p>\n<ul>\n<li><a href=\"#race-conditions-with-useeffect\">Состояние гонки и useEffect</a></li>\n<li><a href=\"#race-conditions-with-componentdidupdate\">Состояние гонки и componentDidUpdate</a></li>\n<li><a href=\"#the-problem\">Проблема</a></li>\n<li><a href=\"#solving-race-conditions-with-suspense\">Решаем состояние гонки используя задержку</a></li>\n</ul>\n</li>\n<li><a href=\"#handling-errors\">Обработка ошибок</a></li>\n<li><a href=\"#next-steps\">Что дальше?</a></li>\n</ul>\n<h2 id=\"what-is-suspense-exactly\"><a href=\"#what-is-suspense-exactly\" 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>Задержка позволяет вашим компонентам «ждать» чего-то до их рендера. В <a href=\"https://codesandbox.io/s/frosty-hermann-bztrp\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">этом примере</a> два компонента ждут асинхронного вызова API, чтобы получить данные:</p>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"token keyword\">const</span> resource <span class=\"token operator\">=</span> <span class=\"token function\">fetchProfileData</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">ProfilePage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Suspense</span></span> <span class=\"token attr-name\">fallback</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Loading profile...</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ProfileDetails</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\">\n      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Suspense</span></span> <span class=\"token attr-name\">fallback</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Loading posts...</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n        </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ProfileTimeline</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\">\n      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Suspense</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Suspense</span></span><span class=\"token punctuation\">></span></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">ProfileDetails</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// Пробуем прочитать информацию о пользователе, хотя она может быть ещё не загружена</span>\n  <span class=\"token keyword\">const</span> user <span class=\"token operator\">=</span> resource<span class=\"token punctuation\">.</span>user<span class=\"token punctuation\">.</span><span class=\"token function\">read</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">return</span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>user<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>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">ProfileTimeline</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// Пробуем прочитать сообщения, хотя они могут быть ещё не загружены</span>\n  <span class=\"token keyword\">const</span> posts <span class=\"token operator\">=</span> resource<span class=\"token punctuation\">.</span>posts<span class=\"token punctuation\">.</span><span class=\"token function\">read</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n      </span><span class=\"token punctuation\">{</span>posts<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">post</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</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 script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>post<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>post<span class=\"token punctuation\">.</span>text<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>\n      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token plain-text\">\n    </span><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 punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><strong><a href=\"https://codesandbox.io/s/frosty-hermann-bztrp\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Посмотреть пример на CodeSandbox</a></strong></p>\n<p>Это раннее демо. Не переживайте, если оно кажется бессмысленным. Мы поговорим о том, как оно работает ниже. Имейте ввиду, что задержка — это больше <em>механизм</em> и определенные API, такие как <code class=\"gatsby-code-text\">fetchProfileData()</code> или <code class=\"gatsby-code-text\">resource.posts.read()</code> в примере выше не очень важны. Если интересно, вы можете найти их определения прямо в <a href=\"https://codesandbox.io/s/frosty-hermann-bztrp\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">демо песочнице</a>.</p>\n<p>Задержка — это не библиотека для получения данных. Это <strong>механизм для библиотек получения данных</strong>, который сообщает React, что <em>данные, которые читает компонент ещё не готовы</em>. React в этом случае может подождать, пока они будут готовы и обновить пользовательский интерфейс. В Facebook, мы используем Relay с <a href=\"https://relay.dev/docs/en/experimental/a-guided-tour-of-relay#loading-states-with-suspense\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">интеграцией новой задержки</a>. Мы ожидаем, что другие библиотеки, такие как Apollo смогут предоставить подобную интеграцию.</p>\n<p>В долгосрочной перспективе мы собираемся сделать задержку основным способом чтения асинхронных данных из компонентов, независимо от того, откуда эти данные пришли.</p>\n<h3 id=\"what-suspense-is-not\"><a href=\"#what-suspense-is-not\" 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>Задержка — это совершенно иной подход среди существующих для решения этих проблем, поэтому на первый взгляд это часто ведёт к заблуждениям. Давайте проясним самые распространенные:</p>\n<ul>\n<li><strong>Это не реализация получения данных.</strong> Задержка не предполагает, что вы используете GraphQL, REST или какой-то другой определённый формат данных, библиотеку, транспорт или протокол.</li>\n<li><strong>Это не готовый к использованию клиент.</strong> Вы не сможете заменить <code class=\"gatsby-code-text\">fetch</code> или Relay задержкой. Но вы можете использовать библиотеку, в которую интегрирована задержка (например <a href=\"https://relay.dev/docs/en/experimental/api-reference\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">новый API у Relay</a>).</li>\n<li><strong>Задержка не привязывает получение данных к слою представления.</strong> Она помогает управлять отображением состояния загрузки в пользовательском интерфейсе, но она не связывает вашу сетевую логику с React-компонентами.</li>\n</ul>\n<h3 id=\"what-suspense-lets-you-do\"><a href=\"#what-suspense-lets-you-do\" 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>Итак, в чём идея задержки? Есть несколько вариантов ответа на этот вопрос:</p>\n<ul>\n<li><strong>Она позволит глубже интегрировать React в библиотеки получения данных.</strong> Если библиотека получения данных реализует поддержку задержки, её использование из React компонентов будет выглядеть естественно.</li>\n<li><strong>Она позволит вам управлять намеренно спроектированными состояниями загрузки.</strong> Она не говорит <em>как</em> данные получены, но позволит вам лучше контролировать визуальную последовательность загрузки вашего приложения.</li>\n<li><strong>Она позволит избежать состояние гонки.</strong> Даже с <code class=\"gatsby-code-text\">await</code> асинхронный код часто подвержен ошибкам. Задержка дает ощущение <em>синхронного</em> чтения данных, как если бы они уже были загружены.</li>\n</ul>\n<h2 id=\"using-suspense-in-practice\"><a href=\"#using-suspense-in-practice\" 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>До настоящего времени в Facebook мы использовали в продакшн только Relay с интегрированной задержкой. <strong>Если вы ищете практическое руководство как начать сегодня, <a href=\"https://relay.dev/docs/en/experimental/step-by-step\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">посмотрите руководство Relay</a>!</strong> Там рассмотрены подходы, которые уже хорошо работают у нас в продакшн.</p>\n<p><strong>Код примеров на этой странице использует «фальшивую» реализацию API, а не Relay.</strong> Это позволяет легче их понимать, если вы не знакомы с GraphQL, но они не расскажут вам о «правильном способе» как построить приложение с использованием задержки. Эта страница скорее о концептуальных принципах и нацелена помочь вам понять <em>почему</em> задержка работает определенным образом и какие проблемы она решает.</p>\n<h3 id=\"what-if-i-dont-use-relay\"><a href=\"#what-if-i-dont-use-relay\" 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>Что, если я не использую Relay? </h3>\n<p>Если вы не используете Relay сегодня, вам возможно придётся подождать, прежде чем вы действительно сможете попробовать задержку в вашем приложении. Это пока что единственная реализация, которую мы протестировали в продакшн и в которой уверены.</p>\n<p>В течение нескольких месяцев, появится много библиотек с различными подходами к API задержки. <strong>Если вы предпочитаете изучать более стабильные технологии, вы можете пока проигнорировать то, что сделано сейчас и вернуться, когда экосистема задержки станет более зрелой.</strong></p>\n<p>Вы можете написать свою собственную интеграцию с библиотекой получения данных, если хотите.</p>\n<h3 id=\"for-library-authors\"><a href=\"#for-library-authors\" 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>Мы ожидаем увидеть в сообществе много экспериментов с другими библиотеками. Есть одна важная деталь на заметку авторам библиотек получения данных.</p>\n<p>Несмотря на то, что это технически выполнимо, задержка сейчас <strong>не</strong> предназначена для получения данных во время рендера компонента. Скорее она позволяет компонентам показать, что они «ждут» данные, которые <em>уже были получены</em>. <strong><a href=\"/blog/2019/11/06/building-great-user-experiences-with-concurrent-mode-and-suspense.html\">Построение хорошего опыта взаимодействия пользователя с интерфейсами в Конкурентном режиме с задержкой</a> описывает почему это важно и как реализовать этот подход на практике.</strong></p>\n<p>Если у вас нет решения, которое помогает предотвращать водопады, мы предлагаем использовать API, которые поддерживают или обеспечивают получение данных до рендера. В качестве конкретного примера, посмотрите как в <a href=\"https://relay.dev/docs/en/experimental/api-reference#usepreloadedquery\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Relay Suspense API</a> организована предзагрузка. Наша информация про это была не очень последовательной. Задержка для получения данных все ещё в экспериментальном режиме, наши рекомендации могут измениться со временем, так как мы учимся новому во время использования технологии в продакшн и лучше понимаем предметную область.</p>\n<h2 id=\"traditional-approaches-vs-suspense\"><a href=\"#traditional-approaches-vs-suspense\" 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>Мы могли бы рассказать о задержке без упоминания популярных способов получения данных. В этом случае было бы сложнее увидеть какие проблемы решает задержка, почему эти проблемы нужно решать и как задержка отличается от существующих решений.</p>\n<p>Наоборот, мы взглянем на задержку, как на следующий логический шаг в перечне подходов:</p>\n<ul>\n<li><strong>«Получаем после рендера»‎ (например, <code class=\"gatsby-code-text\">fetch</code> в <code class=\"gatsby-code-text\">useEffect</code>):</strong> Начинаем рендерить компоненты. Каждый из этих компонентов может вызвать получение данных в своих «эффектах» и методах жизненного цикла. Этот подход обычно ведёт к «водопадам».</li>\n<li><strong>«Получаем потом рендерим»‎ (например, Relay без задержки):</strong> Начинаем получать все данные для следующего экрана как можно раньше. Когда данные готовы — рендерим новый экран. Мы ничего не можем делать пока не получим все данные.</li>\n<li><strong>«Рендерим во время получения данных»‎ (например, Relay с задержкой):</strong> Начинаем получать все требуемые данные для следующего экрана как можно раньше и начинаем рендерить новый экран <em>немедленно — до того, как получим ответ от сети</em>. По мере поступления данных, React повторяет рендер компонентов, которым всё ещё нужны данные, до тех пор, пока они не будут готовы.</li>\n</ul>\n<blockquote>\n<p>Примечание</p>\n<p>Это немного упрощено и на практике требуется использование нескольких подходов. Тем не менее, мы будем рассматривать их отдельно, чтобы лучше отразить компромиссы, которые они требуют.</p>\n</blockquote>\n<p>Для сравнения подходов мы реализуем страницу с профилем пользователя используя каждый из них.</p>\n<h3 id=\"approach-1-fetch-on-render-not-using-suspense\"><a href=\"#approach-1-fetch-on-render-not-using-suspense\" 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>Подход 1: «Получаем после рендера»‎ (задержка не используется) </h3>\n<p>Распространённый сегодня способ получения данных в React с использованием эффекта:</p>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"token comment\">// В функциональном компоненте:</span>\n<span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token function\">fetchSomething</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// Или в классовом компоненте:</span>\n<span class=\"token function\">componentDidMount</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token function\">fetchSomething</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Мы зовем этот подход «получаем после рендера» потому что получение данных начинается <em>после</em> рендера компонента на экране. Это приводит к проблеме, известной как «водопад».</p>\n<p>Взгляните на компоненты <code class=\"gatsby-code-text\">&lt;ProfilePage&gt;</code> и <code class=\"gatsby-code-text\">&lt;ProfileTimeline&gt;</code>:</p>\n<div class=\"gatsby-highlight has-highlighted-lines\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"token keyword\">function</span> <span class=\"token function\">ProfilePage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>user<span class=\"token punctuation\">,</span> setUser<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">fetchUser</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">u</span> <span class=\"token operator\">=></span> <span class=\"token function\">setUser</span><span class=\"token punctuation\">(</span>u<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>user <span class=\"token operator\">===</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Loading profile...</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>user<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>h1</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ProfileTimeline</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span></span><span class=\"token punctuation\">></span></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">ProfileTimeline</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>posts<span class=\"token punctuation\">,</span> setPosts<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">fetchPosts</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">p</span> <span class=\"token operator\">=></span> <span class=\"token function\">setPosts</span><span class=\"token punctuation\">(</span>p<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>posts <span class=\"token operator\">===</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h2</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Loading posts...</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h2</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">      </span><span class=\"token punctuation\">{</span>posts<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">post</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</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 script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>post<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>post<span class=\"token punctuation\">.</span>text<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>\n      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">    </span><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 punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><strong><a href=\"https://codesandbox.io/s/fragrant-glade-8huj6\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Посмотреть пример на CodeSandbox</a></strong></p>\n<p>Если вы запустите этот код в логах консоли вы увидите следующую последовательность:</p>\n<ol>\n<li>Начинаем получать информацию о пользователе</li>\n<li>Ждём…</li>\n<li>Закончили получать информацию о пользователе</li>\n<li>Начинаем получать сообщения пользователя</li>\n<li>Ждём…</li>\n<li>Закончили получать сообщения пользователя</li>\n</ol>\n<p>Если получение информации о пользователе занимает три секунды, мы <em>начнём</em> получать сообщения пользователя только через три секунды! Это «водопад»: непреднамеренная <em>последовательность</em>, которая должна выполняться параллельно.</p>\n<p>Водопады распространены в коде который получает данные после рендера. Их можно устранить, но по мере роста продукта, многие люди предпочитают использовать решение, которое защищает от этой проблемы.</p>\n<h3 id=\"approach-2-fetch-then-render-not-using-suspense\"><a href=\"#approach-2-fetch-then-render-not-using-suspense\" 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>Подход 2: «Получаем потом рендерим»‎ (задержка не используется) </h3>\n<p>Библиотеки могут предотвратить появление водопадов предлагая более централизованный способ получения данных. Например, Relay решает эту проблему перемещением информации о данных, которые нужны компоненту в статически анализируемые <em>фрагменты</em>, которые позже собираются в единый запрос.</p>\n<p>На этой странице, мы не ожидаем, что вы знаете Relay, поэтому не используем его в примере. Вместо этого, мы напишем что-то подобное самостоятельно, комбинируя наши методы получения данных:</p>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"token keyword\">function</span> <span class=\"token function\">fetchProfileData</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> Promise<span class=\"token punctuation\">.</span><span class=\"token function\">all</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span>\n    <span class=\"token function\">fetchUser</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function\">fetchPosts</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">[</span>user<span class=\"token punctuation\">,</span> posts<span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>user<span class=\"token punctuation\">,</span> posts<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>В этом примере <code class=\"gatsby-code-text\">&lt;ProfilePage&gt;</code> ждёт окончания обоих запросов, но запускает их параллельно:</p>\n<div class=\"gatsby-highlight has-highlighted-lines\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"gatsby-highlight-code-line\"><span class=\"token comment\">// Запускаем получение данных как можно раньше</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">const</span> promise <span class=\"token operator\">=</span> <span class=\"token function\">fetchProfileData</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span>\n<span class=\"token keyword\">function</span> <span class=\"token function\">ProfilePage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>user<span class=\"token punctuation\">,</span> setUser<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>posts<span class=\"token punctuation\">,</span> setPosts<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">    promise<span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">data</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token function\">setUser</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">.</span>user<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token function\">setPosts</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">.</span>posts<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>user <span class=\"token operator\">===</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Loading profile...</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>user<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>h1</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ProfileTimeline</span></span> <span class=\"token attr-name\">posts</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>posts<span class=\"token punctuation\">}</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span></span><span class=\"token punctuation\">></span></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// Дочерний компонент теперь не запускает получение данных</span>\n<span class=\"token keyword\">function</span> <span class=\"token function\">ProfileTimeline</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> posts <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>posts <span class=\"token operator\">===</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h2</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Loading posts...</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h2</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">      </span><span class=\"token punctuation\">{</span>posts<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">post</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</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 script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>post<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>post<span class=\"token punctuation\">.</span>text<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>\n      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">    </span><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 punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><strong><a href=\"https://codesandbox.io/s/wandering-morning-ev6r0\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Посмотреть пример на CodeSandbox</a></strong></p>\n<p>Последовательность событий теперь выглядит так:</p>\n<ol>\n<li>Начинаем получать информацию о пользователе</li>\n<li>Начинаем получать сообщения пользователя</li>\n<li>Ждём…</li>\n<li>Закончили получать информацию о пользователе</li>\n<li>Закончили получать сообщения пользователя</li>\n</ol>\n<p>Мы разрешили предыдущий сетевой «водопад», но случайно организовали другой. Мы ждем <em>все</em> данные используя <code class=\"gatsby-code-text\">Promise.all()</code> внутри <code class=\"gatsby-code-text\">fetchProfileData</code>, поэтому мы не можем рендерить профиль пользователя пока все его сообщения не будут получены. Нам приходится ждать и то и другое.</p>\n<p>Конечно, это можно исправить в данном примере. Мы можем убрать вызов <code class=\"gatsby-code-text\">Promise.all()</code> и ждать оба промиса отдельно. Однако этот подход прогрессивно усложняется с увеличением количества данных и ростом дерева компонентов. Сложно писать надежные компоненты когда произвольные части дерева данных могут исчезать или устаревать. Поэтому рендер <em>после</em> получения всех данных для нового экрана часто является более практичным вариантом.</p>\n<h3 id=\"approach-3-render-as-you-fetch-using-suspense\"><a href=\"#approach-3-render-as-you-fetch-using-suspense\" 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>Подход 3: «Рендерим во время получения данных»‎ (используем задержку) </h3>\n<p>В предыдущем подходе мы получали данные перед вызовом <code class=\"gatsby-code-text\">setState</code>:</p>\n<ol>\n<li>Начинаем получать</li>\n<li>Заканчиваем получать</li>\n<li>Начинаем рендерить</li>\n</ol>\n<p>С задержкой мы все ещё начинаем сначала получать данные, но мы меняем последние два пункта местами:</p>\n<ol>\n<li>Начинаем получать</li>\n<li><strong>Начинаем рендерить</strong></li>\n<li><strong>Заканчиваем получать</strong></li>\n</ol>\n<p><strong>С задержкой мы не ждём ответа перед тем, как начать рендерить.</strong> На самом деле, мы начинаем рендерить <em>почти сразу</em> после отправки сетевого запроса:</p>\n<div class=\"gatsby-highlight has-highlighted-lines\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"token comment\">// Это не промис. Это специальный объект из нашей интеграции задержки.</span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">const</span> resource <span class=\"token operator\">=</span> <span class=\"token function\">fetchProfileData</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span>\n<span class=\"token keyword\">function</span> <span class=\"token function\">ProfilePage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Suspense</span></span> <span class=\"token attr-name\">fallback</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Loading profile...</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ProfileDetails</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Suspense</span></span> <span class=\"token attr-name\">fallback</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Loading posts...</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">        </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ProfileTimeline</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Suspense</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Suspense</span></span><span class=\"token punctuation\">></span></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">ProfileDetails</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// Пробуем прочитать информацию о пользователе, хотя она всё ещё может быть не загружена</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> user <span class=\"token operator\">=</span> resource<span class=\"token punctuation\">.</span>user<span class=\"token punctuation\">.</span><span class=\"token function\">read</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span>  <span class=\"token keyword\">return</span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>user<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>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">ProfileTimeline</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// Пробуем прочитать сообщения пользователя, хотя они всё ещё могут быть не загружены</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> posts <span class=\"token operator\">=</span> resource<span class=\"token punctuation\">.</span>posts<span class=\"token punctuation\">.</span><span class=\"token function\">read</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">      </span><span class=\"token punctuation\">{</span>posts<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">post</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</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 script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>post<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>post<span class=\"token punctuation\">.</span>text<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>\n      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">    </span><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 punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><strong><a href=\"https://codesandbox.io/s/frosty-hermann-bztrp\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Посмотреть пример на CodeSandbox</a></strong></p>\n<p>Вот что происходит, когда мы рендерим <code class=\"gatsby-code-text\">&lt;ProfilePage&gt;</code> на экране:</p>\n<ol>\n<li>Мы уже отправили запросы в <code class=\"gatsby-code-text\">fetchProfileData()</code>. Это дает нам специальный «ресурс» вместо промиса. В более реалистичном примере, он был бы предоставлен нашей задержкой интегрированной в библиотеку данных, например Relay.</li>\n<li>React пробует рендерить <code class=\"gatsby-code-text\">&lt;ProfilePage&gt;</code>. Он возвращает <code class=\"gatsby-code-text\">&lt;ProfileDetails&gt;</code> и <code class=\"gatsby-code-text\">&lt;ProfileTimeline&gt;</code> в виде дочерних компонентов.</li>\n<li>React пробует рендерить <code class=\"gatsby-code-text\">&lt;ProfileDetails&gt;</code>. Он вызывает <code class=\"gatsby-code-text\">resource.user.read()</code>. Данные ещё не получены, поэтому компонент «задерживается». React пропускает его и пробует рендерить другие компоненты в дереве.</li>\n<li>React пробует рендерить <code class=\"gatsby-code-text\">&lt;ProfileTimeline&gt;</code>. Он вызывает <code class=\"gatsby-code-text\">resource.posts.read()</code>. Снова, данных ещё нет, этот компонент тоже «задерживается». React пропускает его тоже и пробует рендерить другие компоненты в дереве.</li>\n<li>Больше нечего рендерить. Так как <code class=\"gatsby-code-text\">&lt;ProfileDetails&gt;</code> задерживается, React показывает ближайшую заглушку <code class=\"gatsby-code-text\">&lt;Suspense&gt;</code> поверх него в дереве: <code class=\"gatsby-code-text\">&lt;h1&gt;Loading profile...&lt;/h1&gt;</code>. На данный момент мы закончили.</li>\n</ol>\n<p>Объект <code class=\"gatsby-code-text\">resource</code> представляет данные, которых ещё нет, но они в итоге могут загрузиться. Когда мы вызываем <code class=\"gatsby-code-text\">read()</code>, мы или читаем данные или компонент «задерживается».</p>\n<p><strong>Чем больше потоков данных поступает, React будет пробовать рендерить и каждый раз он сможет продвигаться «глубже».</strong> Когда данные <code class=\"gatsby-code-text\">resource.user</code> получены, компонент <code class=\"gatsby-code-text\">&lt;ProfileDetails&gt;</code> успешно отрендерится и нам больше не потребуется заглушка <code class=\"gatsby-code-text\">&lt;h1&gt;Loading profile...&lt;/h1&gt;</code>. В итоге мы получим все данные и заглушек больше не будет на экране.</p>\n<p>Здесь есть интересный момент. Даже если мы используем клиент GraphQL, который собирает все требования к данным в единый запрос, <em>потоковая передача ответа позволяет нам быстрее показать больше контента</em>. Так как мы рендерим <em>во время получения</em> (в отличии от <em>после</em> получения) и если <code class=\"gatsby-code-text\">user</code> появится в ответе раньше, чем <code class=\"gatsby-code-text\">posts</code>, мы сможем «убрать» внешнюю заглушку <code class=\"gatsby-code-text\">&lt;Suspense&gt;</code> до окончания ответа. Мы могли упустить это ранее, но даже при подходе «получаем потом рендерим»‎ решение содержит водопад: между получением и рендером. Задержка не страдает от этого водопада и библиотеки, такие как Relay пользуются этим.</p>\n<p>Обратите внимание, как мы избавились от проверок <code class=\"gatsby-code-text\">if (...)</code> «идет загрузка» в наших компонентах. Это не только убирает шаблонный код, но и упрощает быстрые изменения в дизайне. Например, если мы хотим, чтобы информация о пользователе и его сообщения всегда появлялись вместе, мы можем удалить разделение <code class=\"gatsby-code-text\">&lt;Suspense&gt;</code> между ними. Или мы можем сделать их независимыми от друг друга, предоставив каждому <em>собственный</em> <code class=\"gatsby-code-text\">&lt;Suspense&gt;</code>. Задержка позволяет нам изменить степень раздробленности наших состояний загрузки и управлять их последовательностью без больших изменений в коде.</p>\n<h2 id=\"start-fetching-early\"><a href=\"#start-fetching-early\" 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>Если вы работает над библиотекой получения данных, есть важный аспект в подходе «рендерим во время получения данных»‎, который не стоит упускать. <strong>Мы запускаем получение данных <em>перед</em> рендером.</strong> Посмотрите внимательно на этот пример:</p>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"token comment\">// Начинаем получать данные рано!</span>\n<span class=\"token keyword\">const</span> resource <span class=\"token operator\">=</span> <span class=\"token function\">fetchProfileData</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// ...</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">ProfileDetails</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// Пытаемся прочитать информацию о пользователе</span>\n  <span class=\"token keyword\">const</span> user <span class=\"token operator\">=</span> resource<span class=\"token punctuation\">.</span>user<span class=\"token punctuation\">.</span><span class=\"token function\">read</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">return</span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>user<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>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><strong><a href=\"https://codesandbox.io/s/frosty-hermann-bztrp\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Посмотреть пример на CodeSandbox</a></strong></p>\n<p>Обратите внимание, что вызов <code class=\"gatsby-code-text\">read()</code> в этом примере не <em>начинает</em> получение данных. Он всего лишь пытается прочитать данные, которые <strong>уже были получены</strong>. Это различие очень важно для создания быстрых приложений с задержкой. Мы не хотим откладывать загрузку данных до начала рендера компонента. Как автор библиотеки получения данных, вы можете предотвратить это сделав невозможным получить объект <code class=\"gatsby-code-text\">resource</code> до начала получения данных. Каждый пример на этой странице использует наш «фальшивый API», который обеспечивает это.</p>\n<p>Вы можете возразить, что получение «в самом начале», как в этом примере — это не практично. Что мы собираемся делать, если перейдем на профиль другого пользователя? Мы хотели бы получать данные на основе пропсов. Ответ на этот вопрос: <strong>вместо этого нужно начать получение данных в обработчике событий</strong>. Ниже упрощенный пример навигации между страницами пользователей:</p>\n<div class=\"gatsby-highlight has-highlighted-lines\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"gatsby-highlight-code-line\"><span class=\"token comment\">// Первое получение данных: как можно скорее</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">const</span> initialResource <span class=\"token operator\">=</span> <span class=\"token function\">fetchProfileData</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span>\n<span class=\"token keyword\">function</span> <span class=\"token function\">App</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>resource<span class=\"token punctuation\">,</span> setResource<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span>initialResource<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>button</span> <span class=\"token attr-name\">onClick</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">const</span> nextUserId <span class=\"token operator\">=</span> <span class=\"token function\">getNextId</span><span class=\"token punctuation\">(</span>resource<span class=\"token punctuation\">.</span>userId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"gatsby-highlight-code-line\">        <span class=\"token comment\">// Следующее получение данных: когда пользователь кликает</span></span><span class=\"gatsby-highlight-code-line\">        <span class=\"token function\">setResource</span><span class=\"token punctuation\">(</span><span class=\"token function\">fetchProfileData</span><span class=\"token punctuation\">(</span>nextUserId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span>      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">        Next</span>\n<span class=\"token plain-text\">      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>button</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ProfilePage</span></span> <span class=\"token attr-name\">resource</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>resource<span class=\"token punctuation\">}</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span></span><span class=\"token punctuation\">></span></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><strong><a href=\"https://codesandbox.io/s/infallible-feather-xjtbu\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Посмотреть пример на CodeSandbox</a></strong></p>\n<p>С таким подходом мы можем <strong>получать код и данные параллельно</strong>. Когда мы перемещаемся между страницами, нам не нужно ждать загрузки кода страницы, чтобы начать получать данные для этой страницы. Мы можем начать получать и данные и код одновременно (во время клика по ссылке), улучшив опыт взаимодействия пользователя с интерфейсом.</p>\n<p>Возникает вопрос, как узнать <em>что</em> получать перед рендером следующего экрана. Есть несколько способов понять это (например, через интеграцию получения данных с роутером). Если вы работаете над библиотекой получения данных, <a href=\"/blog/2019/11/06/building-great-user-experiences-with-concurrent-mode-and-suspense.html\">Построение хорошего опыта взаимодействия пользователя с интерфейсами в Конкурентном режиме с задержкой</a> подробно расскажет о том, как этого добиться и почему это важно.</p>\n<h3 id=\"were-still-figuring-this-out\"><a href=\"#were-still-figuring-this-out\" 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>Задержка — гибкий механизм без большого количества ограничений. А код продукта должен быть более ограничен, чтобы гарантировать отсутствие водопадов и есть различные способы предоставить эти гарантии. На данный момент мы изучаем вопросы, которые включают в себя:</p>\n<ul>\n<li>Раннее получение данных может быть громоздким для написания. Как проще избегать водопадов?</li>\n<li>Когда мы получаем данные для страницы, может ли API включать <em>в себя</em> данные для мгновенных переходов?</li>\n<li>Сколько живёт ответ сервера? Кэширование должно быть локальным или глобальным? Кто управляет кэшем?</li>\n<li>Могут ли прокси помочь организовать ленивую загрузку из API без использования вызовов <code class=\"gatsby-code-text\">read()</code>?</li>\n<li>Как будет выглядеть эквивалент компоновки запросов GraphQL для произвольных данных в задержке?</li>\n</ul>\n<p>Relay отвечает по своему на некоторые из этих вопросов. Есть определенно больше чем один способ сделать это и мы с нетерпением хотим увидеть, какие новые идеи появятся в сообществе разработчиков React.</p>\n<h2 id=\"suspense-and-race-conditions\"><a href=\"#suspense-and-race-conditions\" 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>Состояние гонки — это баги, которые возникают во время неправильного предположения о том, в каком порядке код может исполняться. Получение данных в хуке <code class=\"gatsby-code-text\">useEffect</code> или в жизненных методах класса, например <code class=\"gatsby-code-text\">componentDidUpdate</code> часто приводит к ним. Задержка поможет решить проблему, давайте посмотрим как.</p>\n<p>Для демонстрации проблемы, мы добавим на верхний уровень компонент <code class=\"gatsby-code-text\">&lt;App&gt;</code>, который рендерит наш <code class=\"gatsby-code-text\">&lt;ProfilePage&gt;</code> с кнопкой, которая позволяет <strong>переключаться между разными профилями</strong>:</p>\n<div class=\"gatsby-highlight has-highlighted-lines\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"token keyword\">function</span> <span class=\"token function\">getNextId</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">id</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">App</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>id<span class=\"token punctuation\">,</span> setId<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token plain-text\">      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>button</span> <span class=\"token attr-name\">onClick</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">setId</span><span class=\"token punctuation\">(</span><span class=\"token function\">getNextId</span><span class=\"token punctuation\">(</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token plain-text\">        Next</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token plain-text\">      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>button</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span></span><span class=\"token plain-text\">      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ProfilePage</span></span> <span class=\"token attr-name\">id</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>id<span class=\"token punctuation\">}</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span></span><span class=\"token punctuation\">></span></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Давайте сравним, как разные стратегии получения данных работают с этим требованием.</p>\n<h3 id=\"race-conditions-with-useeffect\"><a href=\"#race-conditions-with-useeffect\" 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>Состояние гонки и <code class=\"gatsby-code-text\">useEffect</code> </h3>\n<p>Сначала мы попробуем версию оригинального примера «получаем в эффекте». Мы модифицируем его для передачи параметра <code class=\"gatsby-code-text\">id</code> из пропсов <code class=\"gatsby-code-text\">&lt;ProfilePage&gt;</code> в <code class=\"gatsby-code-text\">fetchUser(id)</code> и <code class=\"gatsby-code-text\">fetchPosts(id)</code>:</p>\n<div class=\"gatsby-highlight has-highlighted-lines\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">ProfilePage</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> id <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span>  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>user<span class=\"token punctuation\">,</span> setUser<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">fetchUser</span><span class=\"token punctuation\">(</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">u</span> <span class=\"token operator\">=></span> <span class=\"token function\">setUser</span><span class=\"token punctuation\">(</span>u<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>id<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>user <span class=\"token operator\">===</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Loading profile...</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>user<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>h1</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token plain-text\">      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ProfileTimeline</span></span> <span class=\"token attr-name\">id</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>id<span class=\"token punctuation\">}</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\"></span></span><span class=\"token plain-text\">    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span></span><span class=\"token punctuation\">></span></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">ProfileTimeline</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> id <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span>  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>posts<span class=\"token punctuation\">,</span> setPosts<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">fetchPosts</span><span class=\"token punctuation\">(</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">p</span> <span class=\"token operator\">=></span> <span class=\"token function\">setPosts</span><span class=\"token punctuation\">(</span>p<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>id<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>posts <span class=\"token operator\">===</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h2</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Loading posts...</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h2</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">      </span><span class=\"token punctuation\">{</span>posts<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">post</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</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 script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>post<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>post<span class=\"token punctuation\">.</span>text<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>\n      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">    </span><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 punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><strong><a href=\"https://codesandbox.io/s/nervous-glade-b5sel\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Посмотреть пример на CodeSandbox</a></strong></p>\n<p>Обратите внимание, как мы изменили зависимости эффекта с <code class=\"gatsby-code-text\">[]</code> на <code class=\"gatsby-code-text\">[id]</code> — потому что мы хотим перезапускать эффект, когда меняется <code class=\"gatsby-code-text\">id</code>. В противном случае мы не будем получать новые данные.</p>\n<p>Если мы запустим этот код, то на первый взгляд может показаться, что он работает. Однако, если мы сделаем случайным время задержки в реализации нашего «фальшивого API» и быстро нажмем кнопку «Next», мы увидим в логе консоли, что что-то пошло не так. <strong>Запросы из предыдущих профилей могут иногда «возвращаться» после того, как мы переключились на профиль с другим ID, в этом случае они могут перезаписать новое состояние устаревшим ответом от другого ID.</strong></p>\n<p>Эту проблему можно решить (вы можете использовать функцию очистки эффекта, чтобы игнорировать или отклонять устаревшие запросы), но это не интуитивно и усложняет отладку.</p>\n<h3 id=\"race-conditions-with-componentdidupdate\"><a href=\"#race-conditions-with-componentdidupdate\" 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>Состояние гонки и <code class=\"gatsby-code-text\">componentDidUpdate</code> </h3>\n<p>Можно подумать, что проблема специфична для <code class=\"gatsby-code-text\">useEffect</code> или хуков. Возможно, если мы перепишем этот код классами или используем удобный синтаксис <code class=\"gatsby-code-text\">async</code> / <code class=\"gatsby-code-text\">await</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 keyword\">class</span> <span class=\"token class-name\">ProfilePage</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\">React<span class=\"token punctuation\">.</span>Component</span> <span class=\"token punctuation\">{</span>\n  state <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    user<span class=\"token operator\">:</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token function\">componentDidMount</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">fetchData</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>props<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token function\">componentDidUpdate</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">prevProps</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>prevProps<span class=\"token punctuation\">.</span>id <span class=\"token operator\">!==</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>props<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">fetchData</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>props<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token keyword\">async</span> <span class=\"token function\">fetchData</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">id</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> user <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetchUser</span><span class=\"token punctuation\">(</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">setState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> user <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> id <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>props<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> user <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>state<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>user <span class=\"token operator\">===</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">return</span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Loading profile...</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n        </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>user<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>h1</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n        </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ProfileTimeline</span></span> <span class=\"token attr-name\">id</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>id<span class=\"token punctuation\">}</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\">\n      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span></span><span class=\"token punctuation\">></span></span>\n    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">class</span> <span class=\"token class-name\">ProfileTimeline</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\">React<span class=\"token punctuation\">.</span>Component</span> <span class=\"token punctuation\">{</span>\n  state <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    posts<span class=\"token operator\">:</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token function\">componentDidMount</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">fetchData</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>props<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token function\">componentDidUpdate</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">prevProps</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>prevProps<span class=\"token punctuation\">.</span>id <span class=\"token operator\">!==</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>props<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">fetchData</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>props<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token keyword\">async</span> <span class=\"token function\">fetchData</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">id</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> posts <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetchPosts</span><span class=\"token punctuation\">(</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">setState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> posts <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> posts <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>state<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>posts <span class=\"token operator\">===</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">return</span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h2</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Loading posts...</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h2</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n        </span><span class=\"token punctuation\">{</span>posts<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">post</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</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 script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>post<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>post<span class=\"token punctuation\">.</span>text<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>\n        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token plain-text\">\n      </span><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 punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><strong><a href=\"https://codesandbox.io/s/trusting-clarke-8twuq\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Посмотреть пример на CodeSandbox</a></strong></p>\n<p>Этот код обманчиво легко читаем.</p>\n<p>К сожалению, ни использование классов, ни синтаксис <code class=\"gatsby-code-text\">async</code> / <code class=\"gatsby-code-text\">await</code> не помог нам решить эту проблему. Эта версия подвержена состоянию гонки по тем же самым причинам.</p>\n<h3 id=\"the-problem\"><a href=\"#the-problem\" 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 имеют собственный «жизненный цикл». Они могут получать пропсы или обновлять состояние в любой момент времени. Однако, каждый асинхронный запрос <em>тоже</em> имеет собственный «жизненный цикл». Он начинается когда мы его отправляем и заканчивается когда мы получаем ответ. Сложность которую мы испытываем заключается в «синхронизации» нескольких процессов во времени, которые влияют друг на друга. Об этом сложно думать.</p>\n<h3 id=\"solving-race-conditions-with-suspense\"><a href=\"#solving-race-conditions-with-suspense\" 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>Давайте перепишем этот пример с использованием задержки:</p>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"token keyword\">const</span> initialResource <span class=\"token operator\">=</span> <span class=\"token function\">fetchProfileData</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">App</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>resource<span class=\"token punctuation\">,</span> setResource<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span>initialResource<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>button</span> <span class=\"token attr-name\">onClick</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">const</span> nextUserId <span class=\"token operator\">=</span> <span class=\"token function\">getNextId</span><span class=\"token punctuation\">(</span>resource<span class=\"token punctuation\">.</span>userId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token function\">setResource</span><span class=\"token punctuation\">(</span><span class=\"token function\">fetchProfileData</span><span class=\"token punctuation\">(</span>nextUserId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n        Next\n      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>button</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ProfilePage</span></span> <span class=\"token attr-name\">resource</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>resource<span class=\"token punctuation\">}</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\">\n    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span></span><span class=\"token punctuation\">></span></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">ProfilePage</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> resource <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Suspense</span></span> <span class=\"token attr-name\">fallback</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Loading profile...</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ProfileDetails</span></span> <span class=\"token attr-name\">resource</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>resource<span class=\"token punctuation\">}</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\">\n      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Suspense</span></span> <span class=\"token attr-name\">fallback</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Loading posts...</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n        </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ProfileTimeline</span></span> <span class=\"token attr-name\">resource</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>resource<span class=\"token punctuation\">}</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\">\n      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Suspense</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Suspense</span></span><span class=\"token punctuation\">></span></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">ProfileDetails</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> resource <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> user <span class=\"token operator\">=</span> resource<span class=\"token punctuation\">.</span>user<span class=\"token punctuation\">.</span><span class=\"token function\">read</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">return</span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>user<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>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">ProfileTimeline</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> resource <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> posts <span class=\"token operator\">=</span> resource<span class=\"token punctuation\">.</span>posts<span class=\"token punctuation\">.</span><span class=\"token function\">read</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n      </span><span class=\"token punctuation\">{</span>posts<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">post</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</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 script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>post<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>post<span class=\"token punctuation\">.</span>text<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>\n      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token plain-text\">\n    </span><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 punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><strong><a href=\"https://codesandbox.io/s/infallible-feather-xjtbu\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Посмотреть пример на CodeSandbox</a></strong></p>\n<p>В предыдущем примере с задержкой у нас был только один <code class=\"gatsby-code-text\">resource</code>, поэтому мы запишем его в переменную на верхнем уровне. Сейчас у нас несколько ресурсов, мы переместили их в состояние компонента <code class=\"gatsby-code-text\">&lt;App&gt;</code>:</p>\n<div class=\"gatsby-highlight has-highlighted-lines\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"token keyword\">const</span> initialResource <span class=\"token operator\">=</span> <span class=\"token function\">fetchProfileData</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">App</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>resource<span class=\"token punctuation\">,</span> setResource<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span>initialResource<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span></code></pre></div>\n<p>Когда мы кликаем «Next», компонент <code class=\"gatsby-code-text\">&lt;App&gt;</code> делает запрос для следующего профиля и передает <em>этот</em> объект вниз к компоненту <code class=\"gatsby-code-text\">&lt;ProfilePage&gt;</code>:</p>\n<div class=\"gatsby-highlight has-highlighted-lines\" 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></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>button</span> <span class=\"token attr-name\">onClick</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> nextUserId <span class=\"token operator\">=</span> <span class=\"token function\">getNextId</span><span class=\"token punctuation\">(</span>resource<span class=\"token punctuation\">.</span>userId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"gatsby-highlight-code-line\">      <span class=\"token function\">setResource</span><span class=\"token punctuation\">(</span><span class=\"token function\">fetchProfileData</span><span class=\"token punctuation\">(</span>nextUserId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">      Next</span>\n<span class=\"token plain-text\">    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>button</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token plain-text\">    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ProfilePage</span></span> <span class=\"token attr-name\">resource</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>resource<span class=\"token punctuation\">}</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\"></span></span><span class=\"token plain-text\">  </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span></span><span class=\"token punctuation\">></span></span></code></pre></div>\n<p>Снова обратите внимание, что <strong>мы не ждём ответа, чтобы поместить в состояние. Наоборот, мы устанавливаем состояние (и начинаем рендерить) сразу после отправки запроса</strong>. Как только у нас будет больше данных, React «наполнит» содержимым компоненты внутри <code class=\"gatsby-code-text\">&lt;Suspense&gt;</code>.</p>\n<p>Код хорошо читаем, но в отличие от предыдущих примеров, версия с задержкой не подвержена состоянию гонки. Вам интересно почему? В версии с задержкой нам не нужно так много думать о <em>времени</em> в нашем коде. Предыдущие примеры с состоянием гонки требуют установить состояние <em>в правильный момент позднее</em> иначе будет неверно. А с задержкой мы устанавливаем состояние <em>сразу</em>, поэтому здесь сложнее что-то перепутать.</p>\n<h2 id=\"handling-errors\"><a href=\"#handling-errors\" 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>Когда мы пишем код с промисами, мы используем <code class=\"gatsby-code-text\">catch()</code> для обработки ошибок. Как это работает с задержкой, ведь мы не <em>ждём</em> промисов, чтобы начать рендер?</p>\n<p>С задержкой, обработка ошибок при получении данных работает так же, как обработка ошибок при рендере — мы можем рендерить <a href=\"/docs/error-boundaries.html\">предохранитель</a> в любом месте, чтобы «ловить» ошибки в компонентах ниже.</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 comment\">// Предохранители на данный момент должны быть классами.</span>\n<span class=\"token keyword\">class</span> <span class=\"token class-name\">ErrorBoundary</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\">React<span class=\"token punctuation\">.</span>Component</span> <span class=\"token punctuation\">{</span>\n  state <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span> hasError<span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span> error<span class=\"token operator\">:</span> <span class=\"token keyword\">null</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">static</span> <span class=\"token function\">getDerivedStateFromError</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">error</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n      hasError<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n      error\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>state<span class=\"token punctuation\">.</span>hasError<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>props<span class=\"token punctuation\">.</span>fallback<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>props<span class=\"token punctuation\">.</span>children<span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Теперь мы можем добавить его в любую часть дерева, чтобы отлавливать ошибки:</p>\n<div class=\"gatsby-highlight has-highlighted-lines\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"token keyword\">function</span> <span class=\"token function\">ProfilePage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Suspense</span></span> <span class=\"token attr-name\">fallback</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Loading profile...</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ProfileDetails</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\"></span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token plain-text\">      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ErrorBoundary</span></span> <span class=\"token attr-name\">fallback</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h2</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Could not fetch posts.</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h2</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span></span><span class=\"token plain-text\">        </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Suspense</span></span> <span class=\"token attr-name\">fallback</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Loading posts...</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">          </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ProfileTimeline</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\"></span>\n<span class=\"token plain-text\">        </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Suspense</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token plain-text\">      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">ErrorBoundary</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"></span></span><span class=\"token plain-text\">    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Suspense</span></span><span class=\"token punctuation\">></span></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><strong><a href=\"https://codesandbox.io/s/adoring-goodall-8wbn7\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Посмотреть пример на CodeSandbox</a></strong></p>\n<p>Он будет ловить ошибки рендера <em>и</em> ошибки получения данных в задержке. У нас может быть столько предохранителей, сколько мы захотим, но лучше расставлять их <a href=\"https://aweary.dev/fault-tolerance-react/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">избирательно</a>.</p>\n<h2 id=\"next-steps\"><a href=\"#next-steps\" 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>Мы рассмотрели основы задержки для получения данных! Важно, что теперь мы лучше понимаем <em>почему</em> задержка работает таким образом и как вписывается в область получения данных.</p>\n<p>Задержка отвечает на некоторые вопросы, но и поднимает свои собственные:</p>\n<ul>\n<li>Если какой-то компонент «задерживается», то приложением зависает? Как этого избежать?</li>\n<li>Что, если мы хотим показать спиннер в другой части дерева, а не «над» компонентом?</li>\n<li>Если мы намеренно <em>хотим</em> недолго показывать неполный пользовательский интерфейс, можем ли мы это сделать?</li>\n<li>Можем ли мы показывать визуальный эффект затенения текущего экрана вместо спиннера?</li>\n<li>Почему <a href=\"https://codesandbox.io/s/infallible-feather-xjtbu\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">последний пример с задержкой</a> выводит в лог предупреждение, когда мы кликаем по кнопке «Next»?</li>\n</ul>\n<p>Чтобы ответить на эти вопросы, мы ссылаемся на следующий раздел о <a href=\"/docs/concurrent-mode-patterns.html\">Паттернах Конкурентных Пользовательских Интерфейсов</a>.</p>","frontmatter":{"title":"Задержка при получении данных (экспериментально)","next":"concurrent-mode-patterns.html","prev":"concurrent-mode-intro.html"},"fields":{"path":"content/docs/concurrent-mode-suspense.md","slug":"docs/concurrent-mode-suspense.html"}}},"pageContext":{"slug":"docs/concurrent-mode-suspense.html"}},"staticQueryHashes":[]}