React v16.x: план дествий

Ноябрь 27, 2018 Дэн Абрамов


Возможно, вы слышали о таких функциях, как «Hooks», «Suspense» и «Concurrent Rendering» в предыдущих постах и обсуждениях. В этом посте мы рассмотрим, как они сочетаются друг с другом, и ожидаемые сроки их доступности в стабильной версии React.



tl;dr


Мы планируем разделить развертывание новых функций React на следующие этапы:

  • React 16.6 с функцией Suspense (приостановка) для разбиения кода (уже поставлен)

  • Минорный релиз 16.x с функцией Hooks (хуки) (~первый квартал 2019)

  • Минорный релиз 16.x с функцией Concurrent Mode (~второй квартал 2019)

  • Минорный релиз 16.x с функцией Suspense для извлечения данных (Data Fetching) (~середина 2019)


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


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


Мы ожидаем, что их график прояснится в ближайшие месяцы.



Внимание!

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



График релизов


У нас есть единое видение того, как все эти функции сочетаются друг с другом, но мы будем выпускать каждую часть, как только она будет готова, чтобы вы могли ее испытать и начать использовать. Дизайн API не всегда очевиден, если рассматривать каждую часть по отдельности. В этом посте изложены главные части нашего плана, чтобы помочь вам увидеть всю картину. (см. нашу политику управления версиями, чтобы узнать больше о нашей приверженности стабильности.)

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


React 16.6 (поставлен): обладает функцией приостановки для разбиения кода


Под приостановкой понимается новая способность React «приостанавливать» отрисовку, когда компоненты чего-то ждут, и отображать индикатор загрузки. В React 16.6 приостановка поддерживает только один вариант использования: отложенная загрузка компонентов с помощью React.lazy() и <React.Suspense>.


Код
    
  // Данный компонент подгружается динамически
  const OtherComponent = React.lazy(() => import('./OtherComponent'));
  
  function MyComponent() {
    return (
      <React.Suspense fallback={<Spinner />}>
        <div>
          <OtherComponent />
        </div>
        </React.Suspense>
        );
  }
  


Разбиение кода с помощью React.lazy() и <React.Suspense> описано в руководстве по разбиению кода. Однако Вы можете найти и другое практическое объяснение в этой статье.

Мы используем приостановку для разбиения кода в Facebook с июля и ожидаем, что она будет стабильной. В первоначальном публичном релизе в 16.6.0 было несколько регрессий, но они были исправлены в версии 16.6.3.

Разбиение кода - это только первый шаг для функции приостановки. Наше долгосрочное видение этой функции включает в себя возможность обработки извлечения данных (и интеграции с такими библиотеками, как Apollo). В дополнение к удобной модели программирования концепция приостановки также обеспечивает лучшее взаимодействие с пользователем в параллельном режиме. Вы найдете информацию по этим темам ниже.


Статус в React DOM: доступна с React 16.6.0.


Статус в React DOM Server: приостановка еще не доступна в серверной отрисовке. Это не связано с недостатком внимания к данной функции. Мы начали работу над новым асинхронным движком серверной отрисовки, который будет поддерживать приостановку, но это большой проект, и его завершение займет 2019 год.


Статус в React Native: Разделение бандлов не очень полезно в React Native, но технически ничто не мешает React.lazy() и <Suspense> работать при получении Promise для модуля.


Рекомендация: Если вы выполняете только клиентскую отрисовку, мы рекомендуем широко применять React.lazy() и <React.Suspense> для разбиения кода. Если вы выполняете серверную отрисовку, вам придется подождать с использованием, пока новый движок серверной отрисовки не будет готов.


React 16.x (~первый квартал 2019): добавление функции Hooks


Хуки позволяют использовать такие функции, как состояние и жизненный цикл компонентов-функций. Они также позволяют вам повторно использовать логику с отслеживанием состояния между компонентами, не вводя дополнительную вложенность в ваше дерево.


Код
    
  function Example() {
    // Объявление новой переменной состояния, которую мы назовем "count"
    const [count, setCount] = useState(0);
  
    return (
     <div>
       <p>Вы нажали {count} раз</p>
       <button onClick={() => setCount(count + 1)}>
         Click me
       </button>
     </div>
   );
  }
  


Введение и обзор хуков - хорошие источники для начала изучения. Посмотрите данные доклады для ознакомления и глубокого погружения. FAQ должен ответить на большинство ваших дальнейших вопросов. Чтобы узнать больше о мотивах хуков, вы можете прочитать данную статью. Обоснование дизайна API для хуков объясняется в данном ответе в RFC ветке.

Мы работаем с хуками в Facebook с сентября и не ожидаем серьезных ошибок в реализации. Хуки доступны только в 16.7 альфа-версиях React. Ожидается, что некоторые из их API будут изменены в окончательной версии (подробности см. в конце этого комментария). Возможно, что minor версия с хуками может быть не React 16.7.

Хуки представляют наше видение будущего React. Они решают как проблемы, с которыми непосредственно сталкиваются пользователи React («адская оболочка» для render-свойств и компонентов более высокого порядка, дублирование логики в методах жизненного цикла), так и проблемы, с которыми мы столкнулись при оптимизации React в масштабе (например, трудности со встраиванием компонентов с помощью компилятора). Хуки не делают классы устаревшими. Однако, если хуки получат успех, возможно, что в будущем major релизе поддержка классов может быть перенесена в отдельный пакет, уменьшив размер бандла React по умолчанию.


Статус в React DOM: первой версией react и react-dom, поддерживающей хуки, является 16.7.0-alpha.0. Мы ожидаем, что в ближайшие месяцы будет опубликовано больше альфа-версий (на момент написания статьи последней была 16.7.0-alpha.2). Вы можете попробовать их, установив [email protected] и [email protected]. Не забудьте обновить react-dom - иначе хуки не будут работать.


Статус в React DOM Server: те же 16.7 альфа-версии react-dom полностью поддерживают хуки и для react-dom/server.


Статус в React Native: пока что не существует официального сопсоба попробовать хуки в React Native. Если вы любите приключения, ознакомьтесь с неофициальными инструкциями здесь. Существует известная проблема, когда useEffect срабатывает слишком поздно, которая все еще не решена.


Рекомендация: Когда вы будете готовы, мы рекомендуем вам попробовать использование хуков в новых написанных вами компонентах. Убедитесь, что все члены вашей команды знакомы с хуками и этой документацией. Мы не рекомендуем переписывать существующие классы, если вы не планируете их переписывать в любом случае (например, исправлять ошибки). Узнайте больше о стратегии внедрения хуков здесь.


React 16.x (~второй квартал 2019): добавление функции Concurrent Mode


Параллельный режим позволяет приложениям React быть более отзывчивыми, отображая деревья компонентов без блокировки основного потока. Он включен и позволяет React прерывать длительную отрисовку (например, отрисовку новой истории изменений) для обработки события с высоким приоритетом (например, ввода текста(change) или наведения(hover)). Параллельный режим также повышает удобство работы с приостановкой, пропуская ненужные состояния загрузки при быстрых соединениях.



Внимание!

Возможно, вы уже слышали, что параллельный режим ранее назывался «асинхронный режим». Мы изменили название, чтобы подчеркнуть способность React выполнять работу на различных уровнях приоритета. Это отличает его от других подходов к асинхронной отрисовке.


Код
    
  // Два способа включения:

  // 1. Часть приложения (не окончательный API)
  <React.unstable_ConcurrentMode>
    <Something />
  </React.unstable_ConcurrentMode>

  // 2. Всё приложение (не окончательный API)
  ReactDOM.unstable_createRoot(domNode).render(<App />);
  

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

Параллельный режим гораздо менее отточен, чем хуки. Некоторые API еще не настроены должным образом и не выполняют то, что ожидается. На момент написания этого поста мы не рекомендуем использовать параллельный режим ни для чего, кроме экспериментов. Мы не ожидаем много ошибок в самом параллельном режиме, но учтите, что компоненты, которые выдают предупреждения в <React.StrictMode>, могут работать некорректно. Отдельно отметим: мы видели, что в параллельном режиме выявляются проблемы с производительностью в стороннем коде, которые иногда можно принять за проблемы с производительностью в самом параллельном режиме. Например, случайный вызов setInterval(fn, 1), который выполняется каждую миллисекунду, будет давать ухудшающий эффект в параллельном режиме. Мы планируем опубликовать дополнительные рекомендации по диагностике и устранению подобных проблем как часть документации этого релиза.

Параллельный режим - большая часть нашего видения React. Для работы, связанной с процессором это позволяет неблокировать отрисовку и поддерживать отзывчивость вашего приложения при отрисовке сложных деревьев компонентов. Это продемонстрировано в первой части нашего выступления на JSConf Iceland. Параллельный режим также улучшает работу приостановки. Он позволяет избежать мерцания индикатора загрузки, если сеть достаточно быстрая. Трудно объяснить, не наблюдая это вживую, поэтому разговор Эндрю - лучший ресурс, доступный сегодня. В параллельном режиме используется совместный планировщик основных потоков, и мы сотрудничаем с командой Chrome, чтобы в конечном итоге перенести эту функцию в сам браузер.


Статус в React DOM: очень нестабильная версия параллельного режима доступна под префиксом unstable_ в React 16.6, но мы не рекомендуем пробовать ее, если вы не хотите часто сталкиваться со стенами или отсутствующими функциями. Альфа 16.7 включает в себя React.ConcurrentMode и ReactDOM.createRoot без префикса unstable_, но мы, скорее всего, сохраним префикс в 16.7, и пометим параллельный режим как стабильный в этом будущем minor релизе.


Статус в React DOM Server: параллельный режим не влияет напрямую на серверную отрисовку. Он без проблем будет работать с существующим движком.


Статус в React Native: Текущий план - отложить включение параллельного режима в React Native до тех пор, пока проект React Fabric не будет близок к завершению.


Рекомендация: Если вы хотите использовать параллельный режим в будущем, обертывание определенных поддеревьев компонентов в <React.StrictMode> и исправление появляющихся предупреждений - будет хорошим первым шагом. В целом не ожидается, что устаревший код будет абсолютно совместимым. Например, в Facebook мы намереваемся использовать параллельный режим в основном в более свежем коде, а устаревший код в ближайшем будущем будем поддерживать работающим в синхронном режиме.


React 16.x (~второй квартал 2019): добавление приостановки для извлечения данных


Как упоминалось ранее, приостановка относится к способности React «приостанавливать» отрисовку, когда компоненты чего-то ждут, и отображать индикатор загрузки. В уже выпущенном React 16.6 единственным поддерживаемым вариантом использования приостановки является разбиение кода. В будущем minor релизе мы также хотели бы предоставить официально поддерживаемые способы её использования для извлечения данных. Мы предоставим эталонную реализацию базового «React Cache», который совместим с приостановкой, но вы также можете написать и свой собственный. Библиотеки извлечения данных, такие как Apollo и Relay, смогут интегрироваться с приостановкой, следуя простой спецификации, которую мы предоставим.


Код
    
  // React Cache для простого извлечения данных (не окончательный API)
  import {unstable_createResource} from 'react-cache';

  // Скажите React Cache как извлекать ваши данные
  const TodoResource = unstable_createResource(fetchTodo);
  
  function Todo(props) {
    // Приостановка пока данные не окажутся в кеше
    const todo = TodoResource.read(props.id);
    return <li>{todo.title}</li>;
  }
  
  function App() {
    return (
      // Тот же компонент Suspense, который вы уже использовали для разбиения кода
      // может также обрабатывать извлечение данных.
      <React.Suspense fallback={<Spinner />}>
        <ul>
          {/* Siblings fetch in parallel */}
          <Todo id="1" />
          <Todo id="2" />
        </ul>
        </React.Suspense>
    );
  }

  // Сторонние библиотеки, такие как Apollo и Relay также могут
  // предоставлять интеграции приостановки с похожими API.
  


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

Предполагается, что низкоуровневый механизм приостановки (приостанавливающий отрисовку и показывающий резервный UI) будет стабильным даже в React 16.6. Мы использовали его для разбиения кода в продакшене в течение нескольких месяцев. Однако высокоуровневые API для извлечения данных очень нестабильны. React Cache быстро меняется и будет меняться как минимум еще несколько раз. Некоторые низкоуровневые API пока отсутствуют создания для хорошего высокоуровневого API. Мы не рекомендуем использовать React Cache нигде, кроме экспериментов. Обратите внимание, что сам React Cache не привязан строго к релизам React, но в современных альфа-версиях отсутствуют базовые функции, такие как аннулирование кэша, и вы очень скоро столкнетесь со стеной. Мы ожидаем получить что-то полезное с грядущим релизом React.

В конце концов, мы хотели бы, чтобы большая часть выборки данных осуществлялась через приостановку, но потребуется много времени, чтобы все интеграции были готовы. На практике мы ожидаем, что он будет принят очень плавно, и часто через слои, такие как Apollo или Relay, а не напрямую. Отсутствие высокоуровневых API-интерфейсов - не единственное препятствие - есть также некоторые важные шаблоны пользовательского интерфейса, которые мы пока не поддерживаем, такие как отображение индикатора прогресса вне иерархии представления загрузки. Как всегда, мы будем сообщать о наших достижениях в заметках о релизе в этом блоге.


Статус в React DOM и React Native: технически, совместимый кеш уже будет работать с <React.Suspense> в React 16.6. Тем не менее, мы не ожидаем, что у нас будет хорошая реализация кеша, пока не выйдет minor версия React. Если вы желаете авантюры, вы можете попробовать написать собственный кеш, взглянув на альфа-версии React Cache. Тем не менее, обратите внимание, что ментальная модель достаточно отличается, так что существует высокий риск ее неправильного понимания до тех пор, пока не будут готова документация.


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


Рекомендация: Дождитесь minor версии React, чтобы использовать приостановку для извлечения данных. Не пытайтесь для этого использовать функции приостановки в 16.6 - они не поддерживаются. Однако ваши существующие <Suspense> компоненты для разбиения кода также смогут отображать и состояние загрузки данных, когда приостановка для извлечения данных станет поддерживаться официально.



Другие проекты


Модернизация React DOM


Мы начали исследование по упрощению и модернизации ReactDOM с целью уменьшения размера пакета и выравнивания ближе к поведению браузера. Пока еще рано говорить о том, какие конкретные пункты «дойдут до конца», потому что проект находится на стадии исследования. Мы будем сообщать о нашем прогрессе в этом вопросе.


Приостановка для серверной отрисовки


Мы начали проектировать новый движок серверной отрисовки (серверный визуализатор), который поддерживает приостановку (включая ожидание асинхронных данных на сервере без двойной отрисовки) и постепенно загружает и насыщает содержимое страницы порциями для лучшего взаимодействия с пользователем. Вы можете посмотреть обзор его раннего прототипа в этом докладе. Новый движок будет в центре нашего внимания в 2019 году, но пока рано говорить о графике выпуска. Его развитие, как всегда, будет происходить на GitHub.





На этом всё! Как видите, нам есть чем заняться, но мы ожидаем большого прогресса в ближайшие месяцы.

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

Мы всегда открыты для обратной связи и рады услышать ваши отзывы в репозитории RFC, треккере и Твиттере.