Новшества React 16.3(.0-alpha)

https://medium.com/@baphemot/whats-new-in-react-16-3-d2c9b7b6193b
  • Перевод
React 16.3-alpha опубликован в npm, его уже можно загружать и использовать. Сегодня мы поговорим о самых крупных и интересных нововведениях этого релиза. В частности, речь пойдёт об API Context, о новых методах жизненного цикла, о статическом методе getDerivedStateFromProps, о компонентах StrictMode и AsyncMode, а также об обновлённых инструментах разработчика React.

image

Новое API Context


API Context всегда выглядело как нечто таинственное. С одной стороны — это официальное, документированное API React, но, с другой стороны, разработчиков предупреждали о том, что использовать его не следует, так как оно может со временем измениться, и документация по нему, намеренно, была неполной. Теперь время этого API настало, фаза RFC пройдена, и новое API, которое, определённо, стало более дружелюбным, доступно разработчикам. Оно может облегчить вам жизнь, если всё, что вам нужно — простое управление состоянием без «излишеств» Redux или MobX.

Новое API доступно в виде React.createContext(), оно даёт в наше распоряжение два компонента:


Создание нового контекста командой React.createContext

Тут, вызвав фабричную функцию, мы получаем объект, в котором имеются элементы Provider и Consumer.

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


Использование нового API Context — Context.Provider

Тут выбрано поддерево (в данном случае — всё дерево), которому мы хотим передать контекст theme, и установлены значения, которые нужно передать. Значения, конечно, могут быть динамическими (то есть, основанными на this.state).

Следующий шаг заключается в использовании элемента Consumer:


Использование нового API Context — Context.Consumer

Если случилось так, что вы рендерите Consumer не внедряя его в соответствующий Provider, будут использованы значения по умолчанию, объявленные в createContext.
Обратите внимание на следующее:

  • У компонента Consumer должен быть доступ к уже используемому компоненту Context. Если будет создан новый контекст, с теми же входными параметрами, это равносильно созданию нового компонента Context, в результате те данные, которые были в исходном компоненте Context, компоненту Consumer переданы не будут. По этой причине к Context стоит относиться как к компоненту — его нужно создавать один раз, а затем экспортировать или импортировать там, где это нужно.
  • В новом синтаксисе используется шаблон React «функция как потомок» (иногда это называют render prop). Если вы с этим шаблоном не знакомы — взгляните на данный материал.
  • При работе с новыми конструкциями, если планируется использовать новое API Context, больше не нужно использовать prop-types для указания contextProps.

Данные из контекста, передаваемые функции, соответствуют свойству value, установленному в провайдерах компонента Context.provider, и изменение данных в компоненте Provider приводит к перерисовке всех потребителей этих данных.

Новые методы жизненного цикла


Ещё одно новшество, которое, из стадии RFC, перешло в рассматриваемый альфа-релиз React, касается признания устаревшими некоторых методов жизненного цикла и введения нескольких новых методов.

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

Вот функции, которые через некоторое время признают устаревшими:

  • Функция componentWillMount, вместо которой предлагается использовать  componentDidMount.
  • Функция componentWillUpdate, которую заменит componentDidUpdate.
  • Функция componentWillReceiveProps . В качестве заменителя этой функции предлагается новая статическая функция  getDerivedStateFromProps.

В свете вышесказанного не стоит впадать в панику, так как эти функции всё ещё можно использовать. Уведомления о том, что данные функции устарели, появятся в React 16.4, а их удаление запланировано в 17-й версии React.


Паника в стане React-разработчиков. Дэн Абрамов предлагает не беспокоиться, но его слова действуют не на всех

Уведомления будут выводиться только при использовании новых компонентов StrictMode или AsyncMode, но и в этих случаях их можно отключить, используя следующие методы:

  • UNSAFE_componentWillMount
  • UNSAFE_componentWillReceiveProps
  • UNSAFE_componentWillUpdate

Статический метод getDerivedStateFromProps


Так как componentWillReceiveProps собираются убрать, нужны какие-то механизмы для обновления состояния на основании изменения свойств. Для решения этой задачи было решено представить новый статический метод.

Что такое статический метод? Это — метод, который существует в классе, а не в его экземплярах. Пожалуй, легче всего описать этот метод, как такой, у которого нет доступа к this и имеется ключевое слово static в его объявлении.

Однако тут возникает вопрос. Если у функции нет доступа к this, как же вызвать this.setState? Ответ заключается в том, что ничего такого вызывать и не нужно. Функция лишь должна вернуть обновлённые данные состояния, или, если обновление не требуется, null:


Использование getDerivedStateFromProps для обновления состояния

Возвращённое значение ведёт себя точно так же, как текущее значение setState — нужно лишь вернуть изменённую часть состояния, все остальные значения останутся такими же, как были.

Полезные советы по использованию getDerivedStateFromProps


▍Не забудьте инициализировать состояние



Помните о необходимости инициализации состояния

Инициализацию исходного состояния компонента никто не отменял. Делать это надо либо в конструкторе, либо путём настройки поля класса.

▍Особенности вызова getDerivedStateFromProps


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

▍Ошибка при совместном использовании getDerivedStateFromProps и componentWillReceiveProps



Предупреждение, в котором рекомендуется использовать только getDerivedStateFromProps

Если вы объявите и getDerivedStateFromProps, и componentWillReceiveProps, будет вызвана лишь функция getDerivedStateFromProps, а в консоли появится предупреждение.

▍О коллбэках и componentDidUpdate


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

▍О ключевом слове static


Если вы предпочитаете не использовать ключевое слово static, можете использовать альтернативную форму записи:


Объявление getDerivedStateFromProps без использования ключевого слова static

Новый компонент StrictMode


Строгий режим React представлен компонентом, который доступен по адресу React.StrictMode. Его можно добавить в дерево или поддерево приложения:


Использование use strict… Ох, не то. Мы, конечно, имеем в виду компонент StrictMode

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

Если один из дочерних компонентов, выведенных в поддереве StrictMode, использует некоторые из методов, упомянутых выше (вроде componentWillMount), вы увидите сообщение об ошибке в консоли браузера при запуске проекта в режиме разработки:


Ошибка, сообщающая об использовании небезопасных методов жизненного цикла в поддереве StrictMode

Сейчас сообщение об ошибке указывает на RFC, где говорится об удалении методов жизненного цикла.

Новый компонент AsyncMode


Пока ещё неактивный механизм поддержки асинхронных компонентов был переименован так, чтобы его имя соответствовало имени компонента StrictMode. Теперь этот компонент можно найти по адресу React.unsafe_AsyncMode. Использование AsyncMode также активирует уведомления, характерные для StrictMode.

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

Новая версия инструментов разработчика React


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

Если вы используете Chrome, то вам понадобится немного подождать, так как соответствующее расширение в Интернет-магазине Chrome пока не обновлено, а попытки отлаживать старыми инструментами новый код приводят к… интересным результатам:


Рекорд React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED пока ещё не побит

А вот пользователи Firefox уже могут отлаживать новые конструкции:


Новый асинхронный компонент можно видеть при отладке в Firefox

Итоги: самое интересное впереди


Тут мы рассмотрели новшества альфа-релиза React 16.3, однако, стабильная версия этого релиза может содержать в себе другой набор изменений. Если ориентироваться на слова Дэна Абрамова по этому поводу, то React 16.3.0 должен выйти совсем скоро.


На прошлой неделе говорили о следующей неделе, которая уже наступила

Уважаемые читатели! Что вы думаете о новых возможностях React?

RUVDS.com 497,34
RUVDS – хостинг VDS/VPS серверов
Поделиться публикацией
Похожие публикации
Комментарии 50
  • +1
    одному мне кажется очень странным удаление хуков componentWillMount & componentWillUpdate ?
    • +3
      Если обновление state на основе props вынесено в getDerivedStateFromProps, то эти хуки теперь избыточны:
      • Вместо componentWillMount — для сайд-эффектов более оптимальным вариантом будет componentDidMount, а для работы со state и props можно использовать конструктор
      • Вместо componentWillUpdate — для сайд-эффектов предлагается componentDidUpdate, а для работы со state нам дают getDerivedStateFromProps
      • +4
        просто реакт заявляет об обратной совместимости и «мы не такие как ангулар», но при этом переход с 15+ на 16 для основной массы готовых библиотек и компонентов занял пол года, это при том что там впринципе не было ничего сверхестественного только Props вынесли и еще по мелочи (я говорю с точки зрения совместимости старого кода, а не про новый Fiber), а тут изменение API которому 100 лет в обед и на которое, я уверен, завязано достаточно много логики в старом коде, и мне кажется, обновляться они будут еще дольше + не будет возможности обновить библиотеку компонентов на последнюю версию, сохранив старую версию реакта.

        Объединение componentWillMount и componentWillReceiveProps под одним getDerivedStateFromProps имеет смысл, что бы убрать дублирование кода.

        Если говорить без привязки к фреймворкам наличие у компонента
        хуков
        — init

        — willGetParams
        — shouldChange?
        — willMount/willUpdate
        ****** render
        — didUpdate

        — willUnmount
        добавляют гибкости. Даже в ангуларе они появились.

        P.S. вобщем у меня смешаные чувства по поводу грядущего обновления, и мне кажется что он принесет больше пробем чем пользы.
        • –1
          getDerivedStateFromProps не имеет доступа к this, соответственно не может обновлять state, он вроде для определения перерендерить компонент или отменить рендер
          • +1
            Вообще-то, обновлять state — его основная функция. Только делает это он возвращая значение, а не через setState.

            А определением перерендерить или отменить рендер занимается shouldComponentUpdate же…
        • 0

          А для чего вы ими пользовались?


          Для большинства операций больше пододят did-хуки, то есть componentDidMount и componentDidUpdate. Если нужно предотвратить обновление, то есть shouldComponentUpdate.
          will-версии и так не рекомендовались к использованию.

        • –1

          Не кисло так за 4 года 16 версия, они хоть немного совместимы между собой?

          • 0
            Вообще-то они после версии 0.14 выпустили версию 15 вследствие перехода на semver
            • 0
              Вас не удивляет, что Хром за неполных десять лет добрался до версии 64?
            • +2
              Новый контекст теперь работает только в рендере? Если да, то это редкостная кривизна. Тот же MobX'овый Inject как теперь должен работать?
              • 0

                Суть в том что теперь есть обёртка в виде Consumer. А данные из контекста передаются дальше в виде props.

                • +2
                  В виде каких пропс? Вы видели пример? Они передаются в виде аргументов функции-как-потомка. В пропс ничего не передается и из других методов класса контекст не получить
                  • 0

                    Что-то мешает взять пропсы и передать дочернему компоненту?

                    • 0

                      Изобретаем HOC? Мешает то, что получаем ещё 1 уровень вложенности, который усложняет и debugging, и несущественно, но всё же влияет на производительность. У нас и так в сложном приложении повсюду возможны матрёшки из HOC, а так матрёшками нужно покрывать компоненты, которые используют context. Добавить к этому какие-нибудь styled-components, где матрёшкой обёрнут каждый тег со стилями, и получается, что древо компонент почти целиком состоит из композитных матрёшек. С точки зрения приложения — ок, работает же. С остальных точек зрения — спорно, очень спорно.

                      • +1
                        Что значит «изобретаем»? Декоратор inject в mobx-react — это уже HOC, независимо от того нравится вам это или нет.
                        • 0

                          А я про inject в mobx-react и connect в redux-react и не заикался. Это изначально сильно impure-вещи, которые идут как большой компромисс между идеализмом и практикой. Я скорее про тот context, что разработчики по своей воле сами используют в сложных проектах, устав от props-hell. Ниже отписал подробнее.

                          • 0
                            Зато TheShock именно про него и говорил, а я ему отвечал.
                        • 0
                          Изобретаем HOC? Мешает то, что получаем ещё 1 уровень вложенности, который усложняет и debugging, и несущественно, но всё же влияет на производительность. У нас и так в сложном приложении повсюду возможны матрёшки из HOC, а так матрёшками нужно покрывать компоненты, которые используют context. Добавить к этому какие-нибудь styled-components, где матрёшкой обёрнут каждый тег со стилями, и получается, что древо компонент почти целиком состоит из композитных матрёшек. С точки зрения приложения — ок, работает же. С остальных точек зрения — спорно, очень спорно..

                          Используйте для HOC наследование вместо композиции и никаких новых уровней вложенности добавляться не будет
                          • 0

                            Вы знаете, я бы с радостью. Но вот не совсем понимаю, как его тут применить. Судя по тем обрывкам, что я увидел касательно нового API, он работает именно в рамках .render-метода. Ну и по сути асинхронно. Не подскажите рецепт? В голову приходят только разного рода извращения, работающие с задержкой.

                            • –1

                              Да просто использовать те же хокки но только не в виде


                              function hoc(TargetCmponent){
                                return class extends React.Component {
                                 render(){
                                   return <TargetCmponent {...this.props}/>
                                 }
                               }
                              }

                              а в виде


                              function hoc(target){
                                const isTargetClass = target instanceof React.Component
                                return class extends (isTargetClass ? target : React.Component) {
                                  render(){
                                      return isTargetClass ? super.render() : target(this.props) 
                                  }
                                }
                              }

                              и все, больше никаких вложенностей и глубоких матрешек из компонентов-оберток — сколько бы хокков мы бы не навесили на компонент — да хоть тысячу — в рантайме все равно будет создан только один компонент что будет быстрее, так как вызов рендера не создаст тысячу объектов-элементов виртуального дума для этих врапперов, и реакту нужно будет выполнить diff одного компонента а не тысячи

                              • 0

                                Вы, вероятно, имели ввиду примерно это:


                                function hoc(Target, key)
                                {
                                    const isTargetClass = target instanceof React.Component;
                                    const Parent = isTargetClass ? Target : React.Component;
                                    return class extends Parent 
                                    {
                                        render()
                                        {
                                            return <Consumer>{val => 
                                            {
                                                const props = {...this.props, [key]: val };
                                                return isTargetClass 
                                                    ? super.render(props) 
                                                    : target(props);
                                            }}</Consumer>
                                        }
                                    };
                                }

                                Однако в данном случае мы располагаем нужным нам context-полем только внутри super.render. А сложные stateFull компоненты хотят его в других своих методах, включая, возможно, всякие хуки. В теории можно и это обойти, к примеру, задействовав setState. Но тогда мы должны писать компонент из рассчёта на двойной render при инициализации, и, возможно, при одновременной смене чего-нибудь в props и в context (но это уже редкий use case).


                                Идём дальше. Что если нам нужно несколько полей, а не одно? Нужно городить уже достаточно сложную обвязку. Всё выполнимо, но от этого кода сильно несёт… каким-то альтернативным react-ом.

                                • 0
                                  Ну да, с новым контекстом реакта доступ возможен только внутри render-метода. То что этот контекст не будет доступен в разных хуках это проблемы нового контекста. А вообще, если нужно связывать несколько полей, то зачем нужен контекст — не лучше ли использовать внешнее состояние? Я выше привел вариант hoc-ов когда вместо композиции мы используем наследование и избегаем компонентов-оберток в рантайме что позволит улучшить производительность и каких-то минусов по сравнению композиционными hoc-ами я не вижу
                                  • 0
                                    А вообще, если нужно связывать несколько полей, то зачем нужен контекст — не лучше ли использовать внешнее состояние?

                                    Вы имеете внешнее хранилище? Ну вот я использую redux. Но там данные приложения. А вещи которые я пробрасываю через context "руками" другого характера. Сложно объяснить. Ну кроме одной — i18n, по сути переводы и инструментарий к ним.


                                    Да можно написать свой внешний context, по принципу того же redux-react-а. Но это что-то вроде из стрельбы пушки по воробьям. Серьёзное архитектурное решение.


                                    Старый context при всей своей уродливости был в чём-то изящен. Идеологически. Предполагалось, что туда помещают либо совсем что-то impure, и тогда сами ковыряйтесь в этом как хотите (react-redux скажем), либо что-то статическое, и тогда вся машинерия по re-render-у уже не нужна, а вот от килотонн бойлерплейта избавляет.


                                    А новый контекст гораздо больше напоминает прицельные порталы для изменяемых значений. Теперь наследник окольными путями (скажем через import-export) узнаёт что-то от родителя (react в этом совсем не помогает), и позволяет от этого асинхронным образом в render методе зависеть. Вероятно, это выглядит достаточно изящно, при решении каких-то задач. Не знаю.


                                    По поводу внешнего хранилища. Тут ещё встаёт вопрос реализации. Скажем redux-react очень уязвим в вопросе количества подписчиков. Скажем если у вас приложение рендерит сотни или тысячи мелких компонент, то подписываясь в каждом из них на store, вы заставляете connect вычислять mapStateToProps на любой чих (коих может быть очень много). В лучшем случае это просто будет жрать батарейку, в худшем ещё и тормозить.

                                    • 0

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


                                      По поводу внешнего хранилища. Тут ещё встаёт вопрос реализации. Скажем redux-react очень уязвим в вопросе количества подписчиков. Скажем если у вас приложение рендерит сотни или тысячи мелких компонент, то подписываясь в каждом из них на store, вы заставляете connect вычислять mapStateToProps на любой чих (коих может быть очень много). В лучшем случае это просто будет жрать батарейку, в худшем ещё и тормозить.

                                      O, вы обратились по адресу — в статьях тут, тут и тут я разбирал эту проблему и ее решение в виде mobx

                                      • 0
                                        Если контекст у разных поддеревьях компонентов разный то всегда можно выразить эту сутуацию не в через компоненты а через данные.

                                        В случае MobX ― может быть. В случае redux это как-то дорого обходится.

                        • 0

                          А старая концепция context-а, предполагала, что в нём лежат статичные данные, нечто вроде констант, которые не требуется передавать явным образом. Естественно я не имею ввиду redux и прочие динамичные штуки, а скорее какой-нибудь i18n и ему подобные вещи. Это касается в первую очередь сложных приложений, где такой подход работы с контекстном позволяет избежать много-много-многочисленных пробрасываний каких-то обобщённых props по всему большой вложенности древу вниз.


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

                          • 0
                            А i18n и подобные вещи — это тоже вполне себе изменяемые данные, пусть и нечасто изменяемые.
                            • 0

                              Ок, допустим. На самом верхнем уровне, где лежит какой-нибудь <i18n-provider/> можно просто в случае "динамики" (например смены языка) проставить новый key и, хотя мы разово перетрясём всё vdom-древо, мы добьёмся нужных результатов. При том, что на кнопку хорошо если хоть кто-нибудь нажмёт. Мне такой подход показался разумным компромиссом. А теперь же для обеспечения того же функционала, нужно (в моих проектах) покрывать HOC каждый 3-й компонент. Contex позволял обойтись малыми жертвами. А случае использования наследования давался практически бесплатно.

                            • 0

                              Хм. Отдельный момент эти сами .consumer-ы. Если я ничего не напутал, то их нужно передавать по ссылке. Т.е. самым явным образом. Скажем при помощи import-export-а, а это, в свою очередь, усложняет жизнь, не просто лишним бойлерплейтом, а ещё и тем, что если у нас один parent-component, мог порождать несколько вариаций context-значений, исходя из условий, то теперь надо будет как-то самостоятельно разграничивать их своими силами, и react нам в этом больше не помощник.


                              Нет, я конечно ожидал, что context пересмотрят, но чтобы настолько… необычно. Этого вот я не ждал. Мне даже сложно назвать это контекстом. Скорее порталом :)

                            • +1
                              Что-то мешает взять пропсы и передать дочернему компоненту?

                              Вы понимаете зачем нужен контекст? Чтобы не пользоваться пропсами, для того, чтобы гонять по дочерним компонентам всякие вещи типа сторов. По сути, это единственный способ нормального DI в Реакте.

                              А вот вы мне предлагаете, если я хочу воспользоваться контекстом, чтобы не использовать пропсы — использовать пропсы? Тогда зачем вообще нужен такой костыльный контекст, если нужно просто передавать во все компоненты в пропсы еще и контекст вручную?
                        • 0

                          А что случилось-то? Ну делал он раньше var additionalProps = grabStoresFn(this.context.mobxStores || {}, newProps, this.context) || {}, а теперь будет делать


                          <MobxStores.Consumer>
                              {(mobxStores) => {
                                  var additionalProps = grabStoresFn(mobxStores, newProps)
                                  // ...
                                  return createElement(component, newProps)
                              }}
                          </MobxStores.Consumer>

                          Или вы про то, что третий аргумент неоткуда взять теперь? А его вообще кто-то использует? Всегда же он был в состоянии "недодокументирован"...

                          • +1
                            А случилось то, что раньше я мог в любом методе класса обратиться к контексту, а сейчас могу обратиться только в части метода рендер. При чем тут третий аргумент вообще?
                            • 0
                              Вы спрашивали как должен работать inject из mobx-react. Я ответил как.
                              • 0
                                Всмысле «ответили»? Вы совершенно не ответили, как inject будет работать так, чтобы я мог из всех методов пользоваться зависимостями.
                                • 0

                                  В таком случае я не понимаю как вы использовали inject до этого… Документация говорит что его надо использовать вот так:


                                  @inject("color") @observer
                                  class Button extends React.Component {
                                    render() {
                                      return (
                                        <button style={{background: this.props.color}}>
                                          {this.props.children}
                                        </button>
                                      );
                                    }
                                  }

                                  То есть зависимости попадают в props, откуда их можно достать в любом методе.

                                  • 0
                                    Вот именно что «в любом методе».

                                    То есть я могу использовать его так:

                                    @inject("counter") @observer
                                    class MyComponent extends Component<{ id: number, counter: CounterStore }> {
                                      onButtonClick() {
                                        const { id, counter } = this.props;
                                    	
                                        counter.get(id).increaseAction();
                                      }
                                    
                                      render() {
                                        const { id, counter } = this.props;
                                      
                                        return (
                                          <CoolButton onClick={this.onButtonClick}>
                                            {counter.get(id).value}
                                          </CoolButton>
                                        );
                                      }
                                    }


                                    Видите? В любом методе класса, а не только в части метода рендер.
                                    • 0
                                      Раньше inject передавал вам в props тот counter который он достал из контекста в рендере. Теперь inject будет передавать вам в props тот counter который достал Consumer в рендере.

                                      Что поменялось-то?

                                      PS Вы вообще в исходники mobx-react заглядывали? Посмотрите как внутри inject устроен: github.com/mobxjs/mobx-react/blob/master/src/inject.js#L45

                                      Туда Consumer идеально зайдет…
                                      • +1
                                        Посмотрите как внутри inject устроен

                                        Хм, вероятно вы правы, а я — нет. Я заглядывал, но давно. Странно, мне казалось, что он иначе устроен. Последнее время менялся подход?
                        • 0
                          Извините, конечно, может что-то не так понял, но как достучаться до this.state в getDerivedStateFromProps?! this же недоступен…
                          • 0
                            Он же передается вторым параметром…
                            • 0
                              Тупикнул, спасибо (-:
                            • 0

                              До this.state там дотягиваться и не нужно, т.к. он передаётся как параметр метода. А вот до всех остальных полей компонента уже по-нормальному никак. Довольно странное решение, если учесть, в документации открытым текстом сказано, что не стоит помещать в .state поле ничего, что не участвует в .render, мол помещайте "как есть" в this.%property%. Поместили. А теперь туда доступа нет :)

                              • 0
                                Да, уже понял про второй параметр, спасибо… хотя…
                                Как сравнить this.props и nextProps? Вернее, где теперь сравнить props, пришедшие, например, из redux??!
                                • +1
                                  ну, для помещения чего-то в this.%property%, я так понимаю, оставили componentDidUpdate… (если это действительно так необходимо)
                                  • +1

                                    Кстати да. В большинстве не сильно хитрых случаев componentDidUpdate вполне сгодится. Правда вот порылся в своём коде и увидел что у меня есть методы componentWillReceiveProps, которые оперируют offsetWidth и offsetHeight от <SVG/> для формирования нового state. Теперь чтобы иметь к ним доступ нужно этот DOMElement толкать в state. В раздумьях. Насколько здравая идея толкать в .state DOM-элементы, а не данные. Логика подсказывает, что ничего криминального.

                                    • 0
                                      Как минимум — лишний рендер (либо WTF-логика в shouldComponentUpdate), ведь DOM-элемент можно получить только после рендера, а изменение state вызывает рендер.
                                      • 0
                                        ведь DOM-элемент можно получить только после рендера

                                        Дак и componentWillReceiveProps тоже вызывается уже после первого render-а. А касательно того, что DOMElement раньше не получить ― что есть, то есть :) Так уж React устроен.

                              • 0

                                Интересный момент есть, связанный с <Provider/>-ми. Представьте, что вы maintainer redux-а. И вам нужно переехать на новый API. Вы, естественно не хотите, чтобы пользователи из-за обновления стали переписывать все свои container-а. Но что делать? Ведь если мы будем порождать новый Context.{Provider|Consumer} для каждого store-а, а внутри реализации connect-обёртки мы не будем иметь доступ к соответствующему <Consumer/>, и всё накроется медным тазом. Нужно будет пробрасывать store повсеместно. Т.е. переписывать все контейнера. Да и переиспользуемость компонент накроется медным тазом тоже. Они будут явным образом зашиты на один конкретный store.


                                Оказалось, что всё намного проще. redux-react может позволить себе один единственный <Provider/> на всю свою библиотеку, сколько бы store-ов у вас не было. И createContext будет вызван именно внутри библиотеки. Всё дело в том, что один и тот же <Provider/> можно вкладывать в себя же самого сколько душе угодно, и всякий раз при этом менять значение. А каждый <Consumer/> будет иметь доступ только к тому значению, которое ближайшее к нему по древу.


                                Т.е. при первоначальном взгляде на <Provider/> он напоминает телепорт значения сверху внизу, минуя props. На деле же каждый ReactElement порождённый <Provider/>-классом является самостоятельной сущностью со своим собственным значением. Указав во внутреннем <Provider/>-е другое значение, мы значение верхнего не изменим, и вообще ничего не сломается. Они не будут иметь с друг другом ничего общего. Хотя ссылки на <Provider/>-ы и <Cosumer/>-ы будут ===.

                                • 0
                                  Ну это как бы было очевидно…
                                  • 0

                                    Мне нет. Даже в голову не пришло. Более того я уже столько материалов на эту тему нарыл, столько перечитал. Перерыл кучу обсуждений на github-е, RFC посмотрел и все доводы за и против, мотивы решения. Даже стал песочницу собирать. А потом случайно в комментариях на Medium наткнулся на вопрос про вложенность и даже ссылку на рабочий sandbox. И только поковыряв его до меня дошло, как на деле я буду его использовать (несколько вложенных instance от одного и того же Provider-а в одном древе).

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

                                Самое читаемое