Suspense react что это

5 приемов по разделению «бандла» и «ленивой» загрузке компонентов в React

Suspense react что это. image loader. Suspense react что это фото. Suspense react что это-image loader. картинка Suspense react что это. картинка image loader

Разделение Javascript-кода на несколько файлов называется разделением «бандла» или сборки (bundle splitting). Это позволяет загружать только тот код, который который используется приложением в данный момент, другие части загружаются по необходимости (по запросу пользователя).

Распространенные случаи разделения сборки и «ленивой» или отложенной загрузки (lazy loading) включают в себя следующее:

Загрузка дополнительного кода при переходе пользователя к новому представлению (view — слой, отвечающий за визуальное отображение)

Загрузка такого кода может быть связана с определенным действием, таким как прокрутка или нажатие кнопки

Также можно реализовать предварительную загрузку определенных ресурсов, которые представляют потенциальный интерес для пользователя

Это приводит к тому, что когда пользователь захочет получить доступ к определенной функциональности, она уже будет готова

Suspense react что это. 59639feedd5d39606912d761e9fbb5f1. Suspense react что это фото. Suspense react что это-59639feedd5d39606912d761e9fbb5f1. картинка Suspense react что это. картинка 59639feedd5d39606912d761e9fbb5f1

1. Динамический импорт с помощью Webpack

Webpack позволяет загружать модули (компоненты) динамически во время выполнения кода. Рассмотрим пример:

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

Динамический импорт позволяет каждому компоненту выступать в роли микрофронтенда (microfrontend).

2. Split API для загрузки React-компонентов

Резервного компонента при возникновении ошибки

«Настоящего» компонента после загрузки сборки

Рассматриваемый интерфейс облегчает задачу разделения React-компонентов, позволяя избежать повторения шаблонного кода.

Разделение компонентов верхнего уровня на основе маршрутов — еще одна техника оптимизации, способ уменьшения времени загрузки приложения.

В целом, отложенная загрузка кода до запроса пользователем страницы по конкретному маршруту — это хорошая идея.

В данном случае мы также имеем возможность использовать динамический импорт.

3. Создание «вендорного бандла» (vendor bundle)

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

Вот как можно извлечь вендорный бандл из директории node_modules :

Если после этого вы запустите сборку ( yarn build или npm run build ), то увидите что-то вроде этого:

4. Создание нескольких вендорных бандлов

Обычно, все модули объединяются в один вендорный бандл.

Знаете ли вы, что мы можем создать несколько таких бандлов?

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

5. Ленивая загрузка компонентов с помощью React.lazy()

React.lazy() — это функция, позволяющая рендерить динамически импортируемые компоненты как обычные компоненты.

Динамический импорт с помощью React.lazy() :

Проп fallback принимает любой элемент (компонент). Компонент Suspense может быть помещен на любом родительском по отношению к «ленивому» компоненту уровне.

Suspense может оборачивать как отдельный компонент, так и группу компонентов:

Заключение

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

Это, безусловно, положительно повлияет на пользовательский опыт работы с приложением, поскольку оно станет более быстрым и отзывчивым.

Также не стоит забывать о том, что загруженный JavaScript-код, должен быть разобран и выполнен, что также требует некоторого времени и вычислительной мощности.

Облачные серверы от Маклауд быстрые и безопасные.

Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!

Источник

Ленивая загрузка в React

Suspense react что это. 332871530096785392298954131170745622426. Suspense react что это фото. Suspense react что это-332871530096785392298954131170745622426. картинка Suspense react что это. картинка 332871530096785392298954131170745622426

React использует такие сборщики, как WebPack, для упаковки своего кода и его развертывания в браузере. Этот пакет используется браузером для визуализации вашего приложения React.

Теперь представьте, что вы создаете приложение с сотнями компонентов. По умолчанию, упаковщик объединит все эти компоненты в один bundle.js и загрузит ваше приложение. Это, в свою очередь, увеличит первоначальный размер бандла, что приведет к увеличению времени загрузки.

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

Так, что мы можем сделать, чтобы улучшить нашу работу и не заставлять нашего клиента ждать?

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

Подумайте об этом, у вас есть приложение со следующей структурой:

По умолчанию, когда вы загружаете React приложение, оно загружает все компоненты одновременно. Но требуются ли нам компоненты User Dashboard и Logout, когда пользователь даже не вошел в систему. Первыми мы можем загрузить только компоненты Home и Login / Register, и это уменьшит размер вдвое, увеличив время загрузки. Когда пользователь входит в приложение, мы можем загрузить два других компонента.

Теперь мы знаем, почему давайте начнем с того, КАК?

В этой статье я покажу вам два способа реализации отложенной загрузки

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

У меня есть основной компонент App.js, в котором я буду определять два маршрута:

Использование React.lazy и Suspense

Эта функция была впервые представлена ​​в React версии 16.6.0, чтобы обеспечить ленивую загрузку в экосистеме.

Пока не поддерживается при рендеринге на стороне сервера.

В React мы используем ключевое слово import для извлечения компонента, который в основном является модулем JavaScript.

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

React.lazy делает возможным этот динамический импорт, который также прост в реализации.

На данный момент React.lazy не поддерживает именованные экспорты, поэтому не забудьте использовать экспорт по умолчанию для компонентов, которые вы хотите динамически импортировать.

Как только модуль загружен, он вернет новый пакет с Компонентом, объединенным с предыдущим кодом.

Этот обновленный пакет также обновляется в кеше, то есть после загрузки компонента веб-пакет не будет пытаться импортировать тот же компонент снова.

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

Во-первых, нам нужно импортировать модуль Suspense из React:

Suspense react что это. 13502167567360789590263540977949361199. Suspense react что это фото. Suspense react что это-13502167567360789590263540977949361199. картинка Suspense react что это. картинка 13502167567360789590263540977949361199Компонент входа отображается с использованием React.lazy и Suspense

Чтобы проверить, работают ли наши изменения или нет, мы можем проверить dev-tools:

Suspense react что это. 177354623282041523009515777331887092454. Suspense react что это фото. Suspense react что это-177354623282041523009515777331887092454. картинка Suspense react что это. картинка 1773546232820415230095157773318870924541.chunk вызывается, когда компонент динамически импортируется

Мы также можем определить отоборажение ошибок в Suspense для обработки пользовательских ошибок, если компонент не загружается.

Создание своего собственного HOC

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

Давайте посмотрим на вызов этого HOC, вы можете увидеть сходство вызывающих методов с методом React.lazy.

Suspense react что это. 94416833836432116742183354533365829713. Suspense react что это фото. Suspense react что это-94416833836432116742183354533365829713. картинка Suspense react что это. картинка 94416833836432116742183354533365829713Компонент Register, отображаемый с использованием нашего пользовательского HOC

Как и в приведенном выше примере, давайте проверим dev-tools: 2

Suspense react что это. 60875266814848811984408881225227577771. Suspense react что это фото. Suspense react что это-60875266814848811984408881225227577771. картинка Suspense react что это. картинка 608752668148488119844088812252275777712.chunk загружается

Как мы видим, когда был вызван компонент Register, был отправлен новый чанк с обновленным пакетом.

Вы можете найти репозиторий для приведенного выше примера здесь.

Источник

Suspense for Data Fetching (Experimental)

This page was about experimental features that aren’t yet available in a stable release. It was aimed at early adopters and people who are curious.

Much of the information on this page is now outdated and exists only for archival purposes. Please refer to the React 18 Alpha announcement post for the up-to-date information.

Before React 18 is released, we will replace this page with stable documentation.

React 16.6 added a component that lets you “wait” for some code to load and declaratively specify a loading state (like a spinner) while we’re waiting:

Suspense for Data Fetching is a new feature that lets you also use to declaratively “wait” for anything else, including data. This page focuses on the data fetching use case, but it can also wait for images, scripts, or other asynchronous work.

What Is Suspense, Exactly?

Suspense lets your components “wait” for something before they can render. In this example, two components wait for an asynchronous API call to fetch some data:

This demo is a teaser. Don’t worry if it doesn’t quite make sense yet. We’ll talk more about how it works below. Keep in mind that Suspense is more of a mechanism, and particular APIs like fetchProfileData() or resource.posts.read() in the above example are not very important. If you’re curious, you can find their definitions right in the demo sandbox.

Suspense is not a data fetching library. It’s a mechanism for data fetching libraries to communicate to React that the data a component is reading is not ready yet. React can then wait for it to be ready and update the UI. At Facebook, we use Relay and its new Suspense integration. We expect that other libraries like Apollo can provide similar integrations.

In the long term, we intend Suspense to become the primary way to read asynchronous data from components — no matter where that data is coming from.

What Suspense Is Not

Suspense is significantly different from existing approaches to these problems, so reading about it for the first time often leads to misconceptions. Let’s clarify the most common ones:

What Suspense Lets You Do

So what’s the point of Suspense? There are a few ways we can answer this:

Using Suspense in Practice

At Facebook, so far we have only used the Relay integration with Suspense in production. If you’re looking for a practical guide to get started today, check out the Relay Guide! It demonstrates patterns that have already worked well for us in production.

The code demos on this page use a “fake” API implementation rather than Relay. This makes them easier to understand if you’re not familiar with GraphQL, but they won’t tell you the “right way” to build an app with Suspense. This page is more conceptual and is intended to help you see why Suspense works in a certain way, and which problems it solves.

What If I Don’t Use Relay?

If you don’t use Relay today, you might have to wait before you can really try Suspense in your app. So far, it’s the only implementation that we tested in production and are confident in.

Over the next several months, many libraries will appear with different takes on Suspense APIs. If you prefer to learn when things are more stable, you might prefer to ignore this work for now, and come back when the Suspense ecosystem is more mature.

You can also write your own integration for a data fetching library, if you’d like.

For Library Authors

We expect to see a lot of experimentation in the community with other libraries. There is one important thing to note for data fetching library authors.

Although it’s technically doable, Suspense is not currently intended as a way to start fetching data when a component renders. Rather, it lets components express that they’re “waiting” for data that is already being fetched. Building Great User Experiences with Concurrent Mode and Suspense describes why this matters and how to implement this pattern in practice.

Unless you have a solution that helps prevent waterfalls, we suggest to prefer APIs that favor or enforce fetching before render. For a concrete example, you can look at how Relay Suspense API enforces preloading. Our messaging about this hasn’t been very consistent in the past. Suspense for Data Fetching is still experimental, so you can expect our recommendations to change over time as we learn more from production usage and understand the problem space better.

Traditional Approaches vs Suspense

We could introduce Suspense without mentioning the popular data fetching approaches. However, this makes it more difficult to see which problems Suspense solves, why these problems are worth solving, and how Suspense is different from the existing solutions.

Instead, we’ll look at Suspense as a logical next step in a sequence of approaches:

This is a bit simplified, and in practice solutions tend to use a mix of different approaches. Still, we will look at them in isolation to better contrast their tradeoffs.

To compare these approaches, we’ll implement a profile page with each of them.

Approach 1: Fetch-on-Render (not using Suspense)

A common way to fetch data in React apps today is to use an effect:

We call this approach “fetch-on-render” because it doesn’t start fetching until after the component has rendered on the screen. This leads to a problem known as a “waterfall”.

If you run this code and watch the console logs, you’ll notice the sequence is:

If fetching user details takes three seconds, we’ll only start fetching the posts after three seconds! That’s a “waterfall”: an unintentional sequence that should have been parallelized.

Waterfalls are common in code that fetches data on render. They’re possible to solve, but as the product grows, many people prefer to use a solution that guards against this problem.

Approach 2: Fetch-Then-Render (not using Suspense)

Libraries can prevent waterfalls by offering a more centralized way to do data fetching. For example, Relay solves this problem by moving the information about the data a component needs to statically analyzable fragments, which later get composed into a single query.

On this page, we don’t assume knowledge of Relay, so we won’t be using it for this example. Instead, we’ll write something similar manually by combining our data fetching methods:

waits for both requests but starts them in parallel:

The event sequence now becomes like this:

Of course, this is possible to fix in this particular example. We could remove the Promise.all() call, and wait for both Promises separately. However, this approach gets progressively more difficult as the complexity of our data and component tree grows. It’s hard to write reliable components when arbitrary parts of the data tree may be missing or stale. So fetching all data for the new screen and then rendering is often a more practical option.

Approach 3: Render-as-You-Fetch (using Suspense)

In the previous approach, we fetched data before we called setState :

With Suspense, we still start fetching first, but we flip the last two steps around:

With Suspense, we don’t wait for the response to come back before we start rendering. In fact, we start rendering pretty much immediately after kicking off the network request:

Here’s what happens when we render

suspended, React shows the closest fallback above it in the tree:

Loading profile.

As more data streams in, React will retry rendering, and each time it might be able to progress “deeper”. When resource.user is fetched, the

component will render successfully and we’ll no longer need the

Loading profile.

Note how we eliminated the if (. ) “is loading” checks from our components. This doesn’t only remove boilerplate code, but it also simplifies making quick design changes. For example, if we wanted profile details and posts to always “pop in” together, we could delete the boundary between them. Or we could make them independent from each other by giving each its own boundary. Suspense lets us change the granularity of our loading states and orchestrate their sequencing without invasive changes to our code.

Start Fetching Early

If you’re working on a data fetching library, there’s a crucial aspect of Render-as-You-Fetch you don’t want to miss. We kick off fetching before rendering. Look at this code example closer:

Note that the read() call in this example doesn’t start fetching. It only tries to read the data that is already being fetched. This difference is crucial to creating fast applications with Suspense. We don’t want to delay loading data until a component starts rendering. As a data fetching library author, you can enforce this by making it impossible to get a resource object without also starting a fetch. Every demo on this page using our “fake API” enforces this.

You might object that fetching “at the top level” like in this example is impractical. What are we going to do if we navigate to another profile’s page? We might want to fetch based on props. The answer to this is we want to start fetching in the event handlers instead. Here is a simplified example of navigating between user’s pages:

With this approach, we can fetch code and data in parallel. When we navigate between pages, we don’t need to wait for a page’s code to load to start loading its data. We can start fetching both code and data at the same time (during the link click), delivering a much better user experience.

This poses a question of how do we know what to fetch before rendering the next screen. There are several ways to solve this (for example, by integrating data fetching closer with your routing solution). If you work on a data fetching library, Building Great User Experiences with Concurrent Mode and Suspense presents a deep dive on how to accomplish this and why it’s important.

We’re Still Figuring This Out

Suspense itself as a mechanism is flexible and doesn’t have many constraints. Product code needs to be more constrained to ensure no waterfalls, but there are different ways to provide these guarantees. Some questions that we’re currently exploring include:

Relay has its own answers to some of these questions. There is certainly more than a single way to do it, and we’re excited to see what new ideas the React community comes up with.

Suspense and Race Conditions

Race conditions are bugs that happen due to incorrect assumptions about the order in which our code may run. Fetching data in the useEffect Hook or in class lifecycle methods like componentDidUpdate often leads to them. Suspense can help here, too — let’s see how.

To demonstrate the issue, we will add a top-level component that renders our

with a button that lets us switch between different profiles:

Let’s compare how different data fetching strategies deal with this requirement.

Race Conditions with useEffect

First, we’ll try a version of our original “fetch in effect” example. We’ll modify it to pass an id parameter from the

props to fetchUser(id) and fetchPosts(id) :

Note how we also changed the effect dependencies from [] to [id] — because we want the effect to re-run when the id changes. Otherwise, we wouldn’t refetch new data.

If we try this code, it might seem like it works at first. However, if we randomize the delay time in our “fake API” implementation and press the “Next” button fast enough, we’ll see from the console logs that something is going very wrong. Requests from the previous profiles may sometimes “come back” after we’ve already switched the profile to another ID — and in that case they can overwrite the new state with a stale response for a different ID.

This problem is possible to fix (you could use the effect cleanup function to either ignore or cancel stale requests), but it’s unintuitive and difficult to debug.

Race Conditions with componentDidUpdate

This code is deceptively easy to read.

Unfortunately, neither using a class nor the async / await syntax helped us solve this problem. This version suffers from exactly the same race conditions, for the same reasons.

React components have their own “lifecycle”. They may receive props or update state at any point in time. However, each asynchronous request also has its own “lifecycle”. It starts when we kick it off, and finishes when we get a response. The difficulty we’re experiencing is “synchronizing” several processes in time that affect each other. This is hard to think about.

Solving Race Conditions with Suspense

Let’s rewrite this example again, but using Suspense only:

Again, notice that we’re not waiting for the response to set the state. It’s the other way around: we set the state (and start rendering) immediately after kicking off a request. As soon as we have more data, React “fills in” the content inside components.

This code is very readable, but unlike the examples earlier, the Suspense version doesn’t suffer from race conditions. You might be wondering why. The answer is that in the Suspense version, we don’t have to think about time as much in our code. Our original code with race conditions needed to set the state at the right moment later, or otherwise it would be wrong. But with Suspense, we set the state immediately — so it’s harder to mess it up.

When we write code with Promises, we might use catch() to handle errors. How does this work with Suspense, given that we don’t wait for Promises to start rendering?

With Suspense, handling fetching errors works the same way as handling rendering errors — you can render an error boundary anywhere to “catch” errors in components below.

First, we’ll define an error boundary component to use across our project:

And then we can put it anywhere in the tree to catch errors:

It would catch both rendering errors and errors from Suspense data fetching. We can have as many error boundaries as we like but it’s best to be intentional about their placement.

We’ve now covered the basics of Suspense for Data Fetching! Importantly, we now better understand why Suspense works this way, and how it fits into the data fetching space.

Suspense answers some questions, but it also poses new questions of its own:

To answer these questions, we will refer to the next section on Concurrent UI Patterns.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *