{"componentChunkName":"component---src-templates-blog-js","path":"/blog/2019/11/06/building-great-user-experiences-with-concurrent-mode-and-suspense.html","result":{"data":{"markdownRemark":{"html":"<p>Na React Conf 2019 nós anunciamos uma <a href=\"/docs/concurrent-mode-adoption.html#installation\">versão experimental</a> do React que acrescenta suporte ao Modo Concorrente e Suspense. Nesse artigo nós vamos introduzir as melhores práticas para seu uso que nós identificamos durante o processo de construção <a href=\"https://twitter.com/facebook/status/1123322299418124289\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">do novo facebook.com</a>.</p>\n<blockquote>\n<p>Esse artigo será mais relevante para pessoas que trabalham com as <em>bibliotecas de obtenção de dados (data fetching)</em> para React. </p>\n<p>Mostramos como integrar melhor elas com o Modo Concorrente e o Suspense. Os padrões introduzidos aqui são baseados no <a href=\"https://relay.dev/docs/en/experimental/step-by-step\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Relay</a> — nossa biblioteca para construir interfaces de usuário orientadas a dados com GraphQL. De qualquer forma, as ideias desse artigo <strong>se aplicam a outros clientes GraphQL também assim como bibliotecas que usam REST</strong> ou outras abordagens.</p>\n</blockquote>\n<p>Esse artigo é <strong>dedicado aos autores de bibliotecas</strong>. Se você for principalmente desenvolvedor de aplicações, você ainda pode encontrar ideias interessantes aqui, mas não se sinta obrigado a lê-lo inteiramente.</p>\n<h2 id=\"talk-videos\"><a href=\"#talk-videos\" 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>Vídeos de Talks </h2>\n<p>Se você preferir assistir vídeos, algumas das ideias desse artigo foram abordadas em diversas apresentações da React Conf 2019:</p>\n<ul>\n<li><a href=\"https://www.youtube.com/watch?v=Tl0S7QkxFE4&#x26;list=PLPxbbTqCLbGHPxZpw4xj_Wwg8-fdNxJRh&#x26;index=15&#x26;t=0s\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Obtenção de Dados com Suspense no Relay</a> por <a href=\"https://twitter.com/en_JS\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Joe Savona</a></li>\n<li><a href=\"https://www.youtube.com/watch?v=KT3XKDBZW7M&#x26;list=PLPxbbTqCLbGHPxZpw4xj_Wwg8-fdNxJRh&#x26;index=4\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Contruindo o Novo Facebook com React e Relay</a> por <a href=\"https://twitter.com/catchingash\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Ashley Watkins</a></li>\n<li><a href=\"https://www.youtube.com/watch?v=uXEEL9mrkAQ&#x26;list=PLPxbbTqCLbGHPxZpw4xj_Wwg8-fdNxJRh&#x26;index=2\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">React Conf Keynote</a> por <a href=\"https://twitter.com/yuzhiz\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Yuzhi Zheng</a></li>\n</ul>\n<p>Esse artigo apresenta um mergulho na implentação de uma biblioteca de obtenção de dados com Suspense.</p>\n<h2 id=\"putting-user-experience-first\"><a href=\"#putting-user-experience-first\" 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>Colocando a Experiência de Usuário como Prioridade </h2>\n<p>A equipe do React e a comunidade tem constantemente enfatizado a experiência do desenvolvedor: garantindo que o React tenha boas mensagens de erro, focando em componentes como uma maneira de pensar localmente no comportamento do app, desenvolvendo APIs que são previsíveis e encorajando o correto uso via design, etc. Mas nós não temos difundido o suficiente as melhores práticas para garantir uma ótima experiência de <em>usuário</em> em grandes aplicações.</p>\n<p>Por exemplo, a equipe do React tem focado na performance da <em>biblioteca</em> e provido ferramentas para desenvolvedores debugarem e refinarem a performance da aplicação (ex. <code class=\"gatsby-code-text\">React.memo</code>). Mas nós não temos opinado sobre <em>padrões de alto nível</em> que fazem a diferença entre aplicativos rápidos e fluídos e aplicativos lentos e travados. Nós sempre queremos garantir que o React se mantenha acessível a novos usuários e suporte vários de casos uso — nem todo app tem que ser “super” rápido. Mas como uma comunidade nós podemos e devemos sonhar alto. <strong>Nós devemos fazer ser tão fácil quanto possível construir aplicativos que iniciam rápido e continuam rápidos,</strong> mesmo quando eles crescem em complexidade, para usuários utilizando uma variedade de dispositivos e redes no mundo todo. </p>\n<p><a href=\"/docs/concurrent-mode-intro.html\">Modo Concorrente</a> e <a href=\"/docs/concurrent-mode-suspense.html\">Suspense</a> são funcionalidades experimentais que podem ajudar os desenvolvedores a alcançarem esse objetivo. Nós inicialmente apresentamos eles na <a href=\"/blog/2018/03/01/sneak-peek-beyond-react-16.html\">JSConf Iceland em 2018</a>, intencionalmente compartilhando detalhes muito antecipadamente para dar a comunidade tempo para digerir os novos conceitos e para se prepararem para as alterações seguintes. Desde então nós completamos trabalhos correlacionados, como a nova API de Contexto e a introdução do Hooks, que foram desenhados em parte para ajudar os desenvolvedores a escreverem código que seja naturalmente mais compatível com o Modo Concorrente. Mas nós não queremos implementar essas funcionalidades e liberá-las sem garantir que funcionam. Então ao longo do ano passado, as equipes do React, Relay, infraestrutura web, e produto do Facebook têm todas colaborado fortemente para construir uma nova versão do facebook.com que integre profundamente o Modo Concorrente e o Suspense para criar uma experiência com uma sensação mais fluída e similar a de um app. </p>\n<p>Graças a esse projeto, nós estamos mais confiantes do que nunca de que o Modo Concorrente e o Suspense podem tornar mais fácil entregar uma experiência de usuário ótima e <em>rápida</em>. Mas fazer isso requer repensar como nós abordamos o carregamento do código e dos dados em nossos apps. Efetivamente toda a obtenção de dados no novo facebook.com é realizada pelo <a href=\"https://relay.dev/docs/en/experimental/step-by-step\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Relay Hooks</a> — novas APIs do Relay baseadas em Hooks que integram com o Modo Concorrente e o Suspense sem configurações adicionais.</p>\n<p>Relay Hooks — e GraphQL — não são para todos, e tudo bem com isso! Através do nosso trabalho nessas APIs nós identificamos um conjunto de padrões em geral para utilizar com Suspense. <strong>Mesmo que o Relay não se encaixe para você, nós acreditamos que os padrões chave que nós introduzimos com o Relay Hooks podem ser adaptados para outras bibliotecas</strong></p>\n<h2 id=\"best-practices-for-suspense\"><a href=\"#best-practices-for-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>Melhores Práticas com Suspense </h2>\n<p>É tentador focar apenas no tempo total de inicialização de um app — mas ocorre que a percepção de performance pelo usuário é determinada por mais do que o tempo absoluto de carregamento. Por exemplo, quando comparados dois aplicativos com o mesmo tempo absoluto de inicialização, nossos estudos mostram que os usuários geralmente irão perceber aquele que tiver menos estados de carregamento intermediários e menos alterações de layout como o que carrega mais rápido. Suspense é uma ferramenta poderosa por orquestrar cuidadosamente uma elegante sequência de carregamento com poucos, e bem definidos, estados que revelam progressivamente o conteúdo. Mas melhorar a performance percebida vai além disso — nossos apps não deveriam demorar uma eternidade para obter todo o código, dados, imagens, e outros artefatos.</p>\n<p>A abordagem tradicional para carregar dados nos apps React envolvem o que nos referimos como <a href=\"/docs/concurrent-mode-suspense.html#approach-1-fetch-on-render-not-using-suspense\">“renderização-conforme-você-busca”</a>. Primeiro nós renderizamos um componente com um spinner, então carregamos dados na montagem (<code class=\"gatsby-code-text\">componentDidMount</code> ou <code class=\"gatsby-code-text\">useEffect</code>), e finalmente atualizamos para renderizar os dados resultantes. É certamente <em>possível</em> usar esse padrão com Suspense: ao invés de inicialmente renderizar um placeholder por si mesmo, um componente pode “suspender” — indicar ao React que ele não está pronto ainda. Isso irá dizer ao React para buscar o ancestral mais próximo <code class=\"gatsby-code-text\">&lt;Suspense fallback={&lt;Placeholder/&gt;}&gt;</code>, e renderizar o seu fallback no lugar. Se você viu os demos do Suspense anteriormente este exemplo pode parecer familiar — é como nós originalmente imaginamos usar o Suspense para obtenção de dados.</p>\n<p>Ocorre que esta abordagem tem algumas limitações. Considere uma página que mostra uma postagem de mídia social feita por um usuário, com comentários nessa postagem. Ela pode ser estruturada como um componente <code class=\"gatsby-code-text\">&lt;Post&gt;</code> que renderiza tanto o corpo da postagem como a <code class=\"gatsby-code-text\">&lt;CommentList&gt;</code> para mostrar os comentários. Usando a abordagem de renderização-conforme-você-busca descrita acima para implementar isso pode causar idas e voltas sequenciais (muitas vezes conhecido como uma “cachoeira”). Primeiro os dados para o componente <code class=\"gatsby-code-text\">&lt;Post&gt;</code> seriam obtidos e então os dados para a <code class=\"gatsby-code-text\">&lt;CommentList&gt;</code>, aumentando o tempo que para mostrar a página completamente.</p>\n<p>Há também outra desvantagem muitas vezes esquecida nessa abordagem. Se o <code class=\"gatsby-code-text\">&lt;Post&gt;</code> requisita (ou importa) o componente <code class=\"gatsby-code-text\">&lt;CommentList&gt;</code> de maneira completa, nosso app terá de esperar para mostrar o <em>corpo</em> da postagem enquanto o código para os <em>comentários</em> é baixado. Nós poderíamos carregar a <code class=\"gatsby-code-text\">&lt;CommentList&gt;</code> de maneira preguiçosa, mas dessa forma nós iríamos atrasar a obtenção dos dados dos comentários e aumentar o tempo para exibir a página inteira. Como nós resolvemos esse problema sem comprometer a experiência do usuário?</p>\n<h2 id=\"render-as-you-fetch\"><a href=\"#render-as-you-fetch\" 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>Renderização Conforme Você Busca </h2>\n<p>A abordagem de renderização-conforme-você-busca é amplamente utilizada pelos apps React atualmente e pode certamente ser usada para criar ótimos apps. Mas nós conseguiríamos fazer ainda melhor? Vamos voltar um passo atrás e considerar nosso objetivo.</p>\n<p>No exemplo acima do <code class=\"gatsby-code-text\">&lt;Post&gt;</code>, nós idealmente deveríamos mostrar o conteudo mais importante — o corpo da postagem — o mais rápido possível, <em>sem</em> impactar negativamente o tempo para mostrar a página completamente (incluindo comentários). Vamos considerar as restrições em qualquer solução e observar como nós podemos atendê-las:</p>\n<ul>\n<li>Mostrar o conteúdo mais importante (o corpo da postagem) o mais rápido possíve significa que nós precisamos carregar o código e os dados para a visualização de forma incremental. Nós <em>não queremos bloquear a visualização do corpo da postagem</em> enquanto o código da <code class=\"gatsby-code-text\">&lt;CommentList&gt;</code> é baixado, por exemplo.</li>\n<li>Ao mesmo tempo nós não queremos aumentar o tempo para exibição da página completa incluindo comentários. Então nós precisamos <em>começar a carregar o código e os dados para os comentários</em> o mais rápido possível, idealmente <em>em paralelo</em> ao carregamento do corpo da postagem.</li>\n</ul>\n<p>Isso pode soar difícil de alcançar — mas essas restrições são na verdade incrivelmente facilitadoras. Elas descartam uma série de abordagens e nos desenham um rascunho da solução. Isso nós leva aos padrões chave que nós implementamos no Relay Hooks, e que podem ser adaptados para outras biblotecas de obtenção de dados. Veremos cada desses padrões de maneira a entender como podem nos ajudar a alcançar nosso objetivo de experiências de carregamento rápidas e encatadoras:</p>\n<ol>\n<li>Dados em paralelo e árvores de visualização</li>\n<li>Obtenção de dados em manipuladores de evento</li>\n<li>Carregar dados incrementalmente</li>\n<li>Tratar código como dado</li>\n</ol>\n<h3 id=\"parallel-data-and-view-trees\"><a href=\"#parallel-data-and-view-trees\" 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>Dados em Paralelo e Árvores de Visualização </h3>\n<p>Uma das coisas mais atraentes no padrão de renderização-conforme-você-busca é que ele combina <em>quais</em> dados o componente precisa com <em>como</em> renderizar esses dados. Essa combinação é ótima — um exemplo de como faz sentido agrupar código por responsabilidades e não por tecnologias. Todos os problemas que nós vimos acima foram sobre <em>quando</em> nós obtemos os dados nessa abordagem: após a renderização. Nós precisamos precisamos ser capazes de obter dados <em>antes</em> de renderizar o componente. A única forma de alcançar isso é extraindo as dependências de dados em dados em paralelo e árvores de visualização.</p>\n<p>Aqui mostramos como isso funciona no Relay Hooks. Continuando nosso exemplo de uma postagem de mídia social com corpo e comentários, aqui está como definimos isso no Relay Hooks:</p>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"token comment\">// Post.js</span>\n<span class=\"token keyword\">function</span> <span class=\"token function\">Post</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">props</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// Dado uma referência para alguma postagem - `props.post` - *de quais* dados</span>\n  <span class=\"token comment\">// nós precisamos sobre essa postagem?</span>\n  <span class=\"token keyword\">const</span> postData <span class=\"token operator\">=</span> <span class=\"token function\">useFragment</span><span class=\"token punctuation\">(</span>graphql<span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">\n    fragment PostData on Post @refetchable(queryName: \"PostQuery\") {\n      author\n      title\n      # ...  mais campos ...\n    }\n  </span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span> props<span class=\"token punctuation\">.</span>post<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token comment\">// Agora que nós temos os dados, como renderizá-lo?</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>div</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>postData<span class=\"token punctuation\">.</span>title<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>h2</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">by </span><span class=\"token punctuation\">{</span>postData<span class=\"token punctuation\">.</span>author<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\">\n      </span><span class=\"token punctuation\">{</span><span class=\"token comment\">/* mais campos  */</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>div</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>Embora o GraphQL esteja escrito junto ao componente, Relay tem um passo de build (Compilador do Relay) que extrai essas dependências-de-dados em arquivos separados e agrega o GraphQL para cada visualização em uma única consulta. Então nós obtemos os benefícios de combinar responsabilidades, enquanto no tempo de execução temos dados em paralelo e árvores de visualização. Outras bibliotecas poderiam alcançar resultados similares ao permitir que os desenvolvedores definam lógica de obtenção de dados em um arquivo irmão (talvez <code class=\"gatsby-code-text\">Post.data.js</code>), ou então integrar com um bundler para permitir definição de dependência de dados com código de interface de usuário e automaticamente extraí-lo, de maneira semelhante ao Compilador do Relay.</p>\n<p>O segredo é que independente da tecnologia que estamos usando para carregar nossos dados — GraphQL, REST, etc — nós podemos separar <em>quais</em> dados carregar de como e quando fazê-lo. Mas uma vez feito isso, <em>como e quando</em> nós carregamos nossos dados?</p>\n<h3 id=\"fetch-in-event-handlers\"><a href=\"#fetch-in-event-handlers\" 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>Obtenção de Dados em Manipuladores de Evento </h3>\n<p>Imagine que nós estamos para navegar da listagem de postagens de um usuário para a página de uma postagem específica. Nós vamos precisar baixar o código para aquela página — <code class=\"gatsby-code-text\">Post.js</code> — e também obter seus dados.</p>\n<p>Aguardar até que a gente renderize os dados gera os problemas que nós vimos acima. O segredo é começar a obter o código e os dados para a nova visualização <em>no mesmo manipulador de evento que dispara a visualização</em>. Nós ainda podemos obter os dados com nosso roteador — se nosso roteador suporta pré-carregamento de dados para as rotas — ou no evento de clique no link que disparou a navegação. Vale lembrar que os colegas do React Router já trabalharam arduamente para construir APIs para suportarem pré-carregamento de dados para rotas. Mas outras bibliotecas de roteamento podem implementar essa ideia também.</p>\n<p>Conceitualmente, nós queremos que a definição de cada rota inclua duas coisas: qual componente renderizar e que dados pré-carregar, como uma função de rota/parâmetros de url. Aqui está o que esta definição de rota <em>pode</em> parecer. Este exemplo é um pouco inspirado pelas definições de rota do React Router e <em>principalmente se dedica a demonstrar o conceito, não uma API específica</em>:</p>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"token comment\">// PostRoute.js (GraphQL version)</span>\n\n<span class=\"token comment\">// Consulta do Relay para carregamento dos dados do Post</span>\n<span class=\"token keyword\">import</span> PostQuery <span class=\"token keyword\">from</span> <span class=\"token string\">'./__generated__/PostQuery.graphql'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> PostRoute <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// uma expressão que associa qual rota tratar</span>\n  path<span class=\"token operator\">:</span> <span class=\"token string\">'/post/:id'</span><span class=\"token punctuation\">,</span>\n\n  <span class=\"token comment\">// que componente renderizar para essa rota</span>\n  component<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\">'./Post'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n\n  <span class=\"token comment\">// dados a serem carregados para essa rota, como uma função dos parâmetros</span>\n  <span class=\"token comment\">// da rota</span>\n  <span class=\"token function-variable function\">prepare</span><span class=\"token operator\">:</span> <span class=\"token parameter\">routeParams</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// Relay extrai consultas de componentes, nos permitindo referenciar</span>\n    <span class=\"token comment\">// as dependências de dados -- árvore de dados -- de fora.</span>\n    <span class=\"token keyword\">const</span> postData <span class=\"token operator\">=</span> <span class=\"token function\">preloadQuery</span><span class=\"token punctuation\">(</span>PostQuery<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n      postId<span class=\"token operator\">:</span> routeParams<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span> postData <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><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> PostRoute<span class=\"token punctuation\">;</span></code></pre></div>\n<p>Por definição, um roteador pode:</p>\n<ul>\n<li>Associar uma URL a uma definição de rota.</li>\n<li>Chamar a função <code class=\"gatsby-code-text\">prepare()</code> para iniciar o carregamento dos dados da rota. Note que <code class=\"gatsby-code-text\">prepare()</code> é síncrona — <em>nós não queremos esperar pelos dados</em>, dado que nós queremos começar a renderizar as partes mais importantes da visualização (como o corpo da postagem) o mais rápido que possível.</li>\n<li>Passar os dados pré-carregados para o componente. Se o componente estiver pronto — a importação dinâmica do <code class=\"gatsby-code-text\">React.lazy</code> terminou — o componente irá renderizar e tentar acessar os seus dados. Do contrário, o <code class=\"gatsby-code-text\">React.lazy</code> irá suspender até que o código esteja pronto.</li>\n</ul>\n<p>Esta abordagem pode ser generalizada para outras soluções de obtenção de dados. Um app que usa REST poderia definir uma rota dessa forma:</p>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"token comment\">// PostRoute.js (versão em REST)</span>\n\n<span class=\"token comment\">// Lógica escrita manualmente para carregamento dos dados para o componente</span>\n<span class=\"token keyword\">import</span> PostData <span class=\"token keyword\">from</span> <span class=\"token string\">'./Post.data'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> PostRoute <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// uma expressão que associa qual rota tratar</span>\n  path<span class=\"token operator\">:</span> <span class=\"token string\">'/post/:id'</span><span class=\"token punctuation\">,</span>\n\n  <span class=\"token comment\">// que componente renderizar para essa rota</span>\n  component<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\">'./Post'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n\n  <span class=\"token comment\">// dados a serem carregados para essa rota, como uma função dos parâmetros</span>\n  <span class=\"token comment\">// da rota</span>\n  <span class=\"token function-variable function\">prepare</span><span class=\"token operator\">:</span> <span class=\"token parameter\">routeParams</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> postData <span class=\"token operator\">=</span> <span class=\"token function\">preloadRestEndpoint</span><span class=\"token punctuation\">(</span>\n      PostData<span class=\"token punctuation\">.</span>endpointUrl<span class=\"token punctuation\">,</span> \n      <span class=\"token punctuation\">{</span>\n        postId<span class=\"token operator\">:</span> routeParams<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">,</span>\n      <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 keyword\">return</span> <span class=\"token punctuation\">{</span> postData <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><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> PostRoute<span class=\"token punctuation\">;</span></code></pre></div>\n<p>Esta mesma abordagem pode ser empregada não apenas para roteamento, mas em outros lugares onde nós queiramos mostrar conteúdo de maneira preguiçosa ou baseada na interação do usuário. Por exemplo, um componente de aba poderia carregar completamente os dados e o código para a primeira aba, e então usar o mesmo padrão acima para carregar o código e os dados para as outras abas que estão no manipulador de evento de troca de aba. Um componente que mostra um modal poderia pré-carregar o código e os dados para o modal no manipulador de clique que dispara a abertura do modal, e assim por diante.</p>\n<p>Uma vez que implementamos a habilidade de começar a carregar código e dados de uma visualização de maneira independente, nós temos a opção de ir um passo além. Considere um componente <code class=\"gatsby-code-text\">&lt;Link to={path} /&gt;</code> que faz o link para uma rota. Se o usuário passa sobre este link, existe uma chance razoável de que ele irá clicá-lo. E se ele pressionar o mouse, existe uma chance ainda maior de que ele irá completar o clique. Se nós podemos carregar o código e os dados para uma visualização <em>depois</em> de o usuário clicar, nós também podemos iniciar o trabalho <em>antes</em> deles clicarem, começando a preparar a visualização.</p>\n<p>O melhor de tudo, nós podemos centralizar essa lógica em poucos lugares chave — um roteador ou em componentes centralizadores de interação com o usuário — e obter quaisquer benefícios de performance automaticamente em todo nosso app. Claro que pré-carregar nem sempre é benéfico. É algo que um aplicativo pode otimizar baseado no dispositivo do usuário ou velocidade de rede para evitar consumir os planos de dados do usuário. Mas este padrão torna mais fácil centralizar a implementação do pré-carregamento e a decisão de quando habilitá-lo ou não.</p>\n<h3 id=\"load-data-incrementally\"><a href=\"#load-data-incrementally\" 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>Carregar Dados Incrementalmente </h3>\n<p>Os padrões acima — dados em paralelo/árvores de visualização e obtenção em manipuladores de evento — nos permitem iniciar o carregamento dos dados de uma visualização antecipadamente. Mas nós ainda queremos poder mostrar as partes mais importantes da visualização sem ter que esperar por <em>todos</em> os nossos dados. No Facebook nós implementamos o suporte para isso no GraphQL e Relay na forma de algumas novas diretivas de GraphQL (anotações que afetam quando/como os dados são entregues, mas não quais dados). Essas novas diretivas, chamadas <code class=\"gatsby-code-text\">@defer</code> e <code class=\"gatsby-code-text\">@stream</code>, nos permitem recuperar dados de maneira incremental. Por exemplo, considere nosso componente <code class=\"gatsby-code-text\">&lt;Post&gt;</code> acima. Nós queremos mostrar o corpo sem ter que esperar que os comentários estejam prontos. Nós podemos alcançar isso com <code class=\"gatsby-code-text\">@defer</code> e <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 comment\">// Post.js</span>\n<span class=\"token keyword\">function</span> <span class=\"token function\">Post</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">props</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> postData <span class=\"token operator\">=</span> <span class=\"token function\">useFragment</span><span class=\"token punctuation\">(</span>graphql<span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">\n    fragment PostData on Post {\n      author\n      title\n\n      # obter dados para os comentários, mas sem bloquear até que estejam carregados\n      ...CommentList @defer\n    }\n  </span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span> props<span class=\"token punctuation\">.</span>post<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\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>div</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>postData<span class=\"token punctuation\">.</span>title<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>h2</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">by </span><span class=\"token punctuation\">{</span>postData<span class=\"token punctuation\">.</span>author<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\">\n      </span><span class=\"token punctuation\">{</span><span class=\"token comment\">/* @defer trabalha naturalmente com &lt;Suspense> para criar uma interface de usuário não bloqueada também */</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><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\">CommentList</span></span> <span class=\"token attr-name\">post</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>postData<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>div</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>Aqui, nosso servidor GraphQL devolve os resultados por stream, primeiro retornando os campos <code class=\"gatsby-code-text\">author</code> e <code class=\"gatsby-code-text\">title</code> e então retornando os dados de comentário quando estiver pronto. Nós envolvemos a <code class=\"gatsby-code-text\">&lt;CommentList&gt;</code> em uma tag <code class=\"gatsby-code-text\">&lt;Suspense&gt;</code> então nós podemos renderizar o corpo da postagem antes da <code class=\"gatsby-code-text\">&lt;CommentList&gt;</code> e seus dados estarem prontos. Esse padrão pode ser aplicado a outras biblotecas. Por exemplo, apps que chamam uma API REST podem fazer requisições em paralelo para obter os dados para o corpo e comentários para uma postagem evitando bloquear até que todos os dados estejam prontos.</p>\n<h3 id=\"treat-code-like-data\"><a href=\"#treat-code-like-data\" 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>Tratar Código Como Dados </h3>\n<p>Mas ainda tem uma coisa faltando. Nós mostramos como pré-carregar <em>dados</em> para uma rota — mas e o código? O exemplo acima nos enganou um pouco e usou <code class=\"gatsby-code-text\">React.lazy</code>. De qualquer forma, <code class=\"gatsby-code-text\">React.lazy</code> é, como o nome indica, <em>preguiçoso</em>. Ele não irá começar a baixar o código até que o componente preguiçoso esteja renderizado — é uma “obtenção-de-dados-na-renderização” para código!</p>\n<p>Para resolver isso, a equipe do React está considerando APIs que nos permitiriam dividir o bundle e pré-carregar completamente o código também. Isso permitiria um usuário passar de alguma forma um componente preguiçoso para uma rota, e a rota disparar o carregamento do código e dos seus dados o mais antecipadamente possível.</p>\n<h2 id=\"putting-it-all-together\"><a href=\"#putting-it-all-together\" 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>Resumindo </h2>\n<p>Para recaptular, atingir uma ótima experiência de usuário significa que nós precisamos <strong>começar a carregar código e dados o mais antecipadamente possível, mas sem esperar que tudo seja completado</strong>. Dados em paralelo e árvores de visualização nos permitem carregar os dados para uma visualização em paralelo com o carregamento da própria visualização (código). Obtenção de dados em um manipulador de eventos significa que nós podemos começar a carregar os dados o mais antecipadamente possível, e otimamente até mesmo pré-carregar uma visualização quando nós tivermos confiança suficiente de que o usuário irá navegar para ela. Carregar dados de maneira incremental nos permite carregar os dados mais importantes antecipadamente sem atrasar a obtenção de dados de menos importância. E tratar código como dados — e pré-carregar esse código com APIs similares — nos permite carregá-lo de maneira antecipada também.</p>\n<h2 id=\"using-these-patterns\"><a href=\"#using-these-patterns\" 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>Utilizando Esses Padrões </h2>\n<p>Esses padrões não são apenas ideias — nós os implementamos no React Hooks e estamos usando eles em produção ao longo do novo facebook.com (o que está atualmente em teste beta). Se você estiver interessado em utilizá-lo ou aprender mais sobre esses padrões, aqui estão algumas referências:</p>\n<ul>\n<li>A <a href=\"/docs/concurrent-mode-intro.html\">documentação do Modo Concorrente do React</a> aborda como utilizar o Modo Concorrente e o Suspense e detalha melhor vários desses padrões. É uma ótima referência para aprender mais sobre as APIs e casos de uso que elas suportam.</li>\n<li>A <a href=\"https://relay.dev/docs/en/experimental/step-by-step\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">versão experimental do Relay Hooks</a> implementa os padrões descritos aqui. </li>\n<li>\n<p>Nós implementamos dois aplicativos de exemplo que demonstram esses conceitos:</p>\n<ul>\n<li>O <a href=\"https://github.com/relayjs/relay-examples/tree/master/issue-tracker\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">aplicativo exemplo do Relay Hooks</a> utiliza a API GraphQL pública do GitHub para implementar um aplicativo simples de rastreamento de issues. Ele inclui suporte a rotas aninhadas com pré-carregamento de dados e código. O código está totalmente comentado — nós encorajamos clonar o repositório, executar o aplicativo localmente, e explorar como ele funciona.</li>\n<li>Nós também temos uma <a href=\"https://github.com/gaearon/suspense-experimental-github-demo\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">versão de aplicativo não-GraphQL</a> que demonstra como esses conceitos podem ser aplicados para outras bibliotecas de obtenção de dados.</li>\n</ul>\n</li>\n</ul>\n<p>Mesmo que as APIs do Modo Concorrente e Suspense <a href=\"/docs/concurrent-mode-adoption.html#who-is-this-experimental-release-for\">ainda sejam experimentais</a>, nós estamos confiantes que as ideias desse artigo são comprovadas na prática. De qualquer forma, nós entendemos que o Relay e GraphQL não são aplicáveis a todos. E tudo bem! <strong>Nós estamos explorando como generalizar esses padrões para abordagens como REST,</strong> e também explorando ideias para uma API mais genérica (isto é, não-GraphQL) para composição de árvores de dependência de dados. Enquanto isso, estamos animados por ver que novas bibliotecas irão surgir implementando os padrões descritos nesse artigo para criar de maneira mais fácil, experiências de usuário <em>rápidas</em>.</p>","excerpt":"Na React Conf 2019 nós anunciamos uma versão experimental do React que acrescenta suporte ao Modo Concorrente e Suspense. Nesse artigo nós vamos introduzir as melhores práticas para seu uso que nós identificamos durante o processo de construção do novo facebook.com. Esse artigo será mais relevante para pessoas que trabalham com as bibliotecas de obtenção de dados (data fetching) para React.  Mostramos como integrar melhor elas com o Modo Concorrente e o Suspense. Os padrões introduzidos aqui são…","frontmatter":{"title":"Construindo Ótimas Experiências de Usuário com Modo Concorrente e Suspense","next":null,"prev":null,"author":[{"frontmatter":{"name":"Joseph Savona","url":"https://twitter.com/en_JS"}}]},"fields":{"date":"06 de novembro de 2019","path":"content/blog/2019-11-06-building-great-user-experiences-with-concurrent-mode-and-suspense.md","slug":"/blog/2019/11/06/building-great-user-experiences-with-concurrent-mode-and-suspense.html"}},"allMarkdownRemark":{"edges":[{"node":{"frontmatter":{"title":"React v17.0"},"fields":{"slug":"/blog/2020/10/20/react-v17.html"}}},{"node":{"frontmatter":{"title":"Apresentando o novo JSX Transform"},"fields":{"slug":"/blog/2020/09/22/introducing-the-new-jsx-transform.html"}}},{"node":{"frontmatter":{"title":"React v17.0 Candidato à lançamento: Sem novas funcionalidades"},"fields":{"slug":"/blog/2020/08/10/react-v17-rc.html"}}},{"node":{"frontmatter":{"title":"React v16.13.0"},"fields":{"slug":"/blog/2020/02/26/react-v16.13.0.html"}}},{"node":{"frontmatter":{"title":"Construindo Ótimas Experiências de Usuário com Modo Concorrente e Suspense"},"fields":{"slug":"/blog/2019/11/06/building-great-user-experiences-with-concurrent-mode-and-suspense.html"}}},{"node":{"frontmatter":{"title":"Preparando para o Futuro com as Prereleases React"},"fields":{"slug":"/blog/2019/10/22/react-release-channels.html"}}},{"node":{"frontmatter":{"title":"Apresentando o novo React DevTools"},"fields":{"slug":"/blog/2019/08/15/new-react-devtools.html"}}},{"node":{"frontmatter":{"title":"React v16.9.0 e a atualização do Roadmap"},"fields":{"slug":"/blog/2019/08/08/react-v16.9.0.html"}}},{"node":{"frontmatter":{"title":"O React já esta traduzido? ¡Sí! Sim! はい！"},"fields":{"slug":"/blog/2019/02/23/is-react-translated-yet.html"}}},{"node":{"frontmatter":{"title":"React v16.8: O React com Hooks"},"fields":{"slug":"/blog/2019/02/06/react-v16.8.0.html"}}}]}},"pageContext":{"slug":"/blog/2019/11/06/building-great-user-experiences-with-concurrent-mode-and-suspense.html"}},"staticQueryHashes":[]}