React 16.3-alpha опубликован в npm, его уже можно загружать и использовать. Сегодня мы поговорим о самых крупных и интересных нововведениях этого релиза. В частности, речь пойдёт об API Context, о новых методах жизненного цикла, о статическом методе
API Context всегда выглядело как нечто таинственное. С одной стороны — это официальное, документированное API React, но, с другой стороны, разработчиков предупреждали о том, что использовать его не следует, так как оно может со временем измениться, и документация по нему, намеренно, была неполной. Теперь время этого API настало, фаза RFC пройдена, и новое API, которое, определённо, стало более дружелюбным, доступно разработчикам. Оно может облегчить вам жизнь, если всё, что вам нужно — простое управление состоянием без «излишеств» Redux или MobX.
Новое API доступно в виде
Создание нового контекста командой React.createContext
Тут, вызвав фабричную функцию, мы получаем объект, в котором имеются элементы
Использование нового API Context — Context.Provider
Тут выбрано поддерево (в данном случае — всё дерево), которому мы хотим передать контекст
Следующий шаг заключается в использовании элемента
Использование нового API Context — Context.Consumer
Если случилось так, что вы рендерите
Обратите внимание на следующее:
Данные из контекста, передаваемые функции, соответствуют свойству
Ещё одно новшество, которое, из стадии RFC, перешло в рассматриваемый альфа-релиз React, касается признания устаревшими некоторых методов жизненного цикла и введения нескольких новых методов.
Это изменение нацелено на внедрение рекомендованных подходов к разработке (вот материал о том, почему с этими функциями может быть непросто обращаться), что обретёт особую важность после того, как будет полностью активирован асинхронный режим рендеринга (что является одной из важнейших целей архитектуры Fiber, появившейся в React 16).
Вот функции, которые через некоторое время признают устаревшими:
В свете вышесказанного не стоит впадать в панику, так как эти функции всё ещё можно использовать. Уведомления о том, что данные функции устарели, появятся в React 16.4, а их удаление запланировано в 17-й версии React.
Паника в стане React-разработчиков. Дэн Абрамов предлагает не беспокоиться, но его слова действуют не на всех
Уведомления будут выводиться только при использовании новых компонентов
Так как
Что такое статический метод? Это — метод, который существует в классе, а не в его экземплярах. Пожалуй, легче всего описать этот метод, как такой, у которого нет доступа к
Однако тут возникает вопрос. Если у функции нет доступа к
Использование getDerivedStateFromProps для обновления состояния
Возвращённое значение ведёт себя точно так же, как текущее значение
Помните о необходимости инициализации состояния
Инициализацию исходного состояния компонента никто не отменял. Делать это надо либо в конструкторе, либо путём настройки поля класса.
Рассматриваемая функция вызывается и при первоначальном монтировании, и при перерисовке компонента, поэтому вы можете использовать её вместо создания в конструкторе состояния, основанного на свойствах.
Предупреждение, в котором рекомендуется использовать только getDerivedStateFromProps
Если вы объявите и
Если обычно вы применяете коллбэки для того, чтобы обеспечить выполнение некоего кода после успешного обновления состояния, теперь, вместо коллбэков, используйте
Если вы предпочитаете не использовать ключевое слово
Объявление getDerivedStateFromProps без использования ключевого слова static
Строгий режим React представлен компонентом, который доступен по адресу
Использование use strict… Ох, не то. Мы, конечно, имеем в виду компонент StrictMode
Смысл использования
Если один из дочерних компонентов, выведенных в поддереве
Ошибка, сообщающая об использовании небезопасных методов жизненного цикла в поддереве StrictMode
Сейчас сообщение об ошибке указывает на RFC, где говорится об удалении методов жизненного цикла.
Пока ещё неактивный механизм поддержки асинхронных компонентов был переименован так, чтобы его имя соответствовало имени компонента
Если вы хотите узнать подробности об асинхронных компонентах 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?
getDerivedStateFromProps
, о компонентах StrictMode
и AsyncMode
, а также об обновлённых инструментах разработчика React.Новое 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?
vitvad
одному мне кажется очень странным удаление хуков componentWillMount & componentWillUpdate ?
NicoBurno
Если обновление state на основе props вынесено в getDerivedStateFromProps, то эти хуки теперь избыточны:
vitvad
просто реакт заявляет об обратной совместимости и «мы не такие как ангулар», но при этом переход с 15+ на 16 для основной массы готовых библиотек и компонентов занял пол года, это при том что там впринципе не было ничего сверхестественного только Props вынесли и еще по мелочи (я говорю с точки зрения совместимости старого кода, а не про новый Fiber), а тут изменение API которому 100 лет в обед и на которое, я уверен, завязано достаточно много логики в старом коде, и мне кажется, обновляться они будут еще дольше + не будет возможности обновить библиотеку компонентов на последнюю версию, сохранив старую версию реакта.
Объединение componentWillMount и componentWillReceiveProps под одним getDerivedStateFromProps имеет смысл, что бы убрать дублирование кода.
Если говорить без привязки к фреймворкам наличие у компонента
— willGetParams
— shouldChange?
— willMount/willUpdate
****** render
— didUpdate
— willUnmount
Hazrat
getDerivedStateFromProps не имеет доступа к this, соответственно не может обновлять state, он вроде для определения перерендерить компонент или отменить рендер
mayorovp
Вообще-то, обновлять state — его основная функция. Только делает это он возвращая значение, а не через setState.
А определением перерендерить или отменить рендер занимается shouldComponentUpdate же…
justboris
А для чего вы ими пользовались?
Для большинства операций больше пододят did-хуки, то есть componentDidMount и componentDidUpdate. Если нужно предотвратить обновление, то есть shouldComponentUpdate.
will-версии и так не рекомендовались к использованию.
alex6636
Не кисло так за 4 года 16 версия, они хоть немного совместимы между собой?
Valery4
Вообще-то они после версии 0.14 выпустили версию 15 вследствие перехода на semver
Valery4
Вас не удивляет, что Хром за неполных десять лет добрался до версии 64?
TheShock
Новый контекст теперь работает только в рендере? Если да, то это редкостная кривизна. Тот же MobX'овый Inject как теперь должен работать?
parmactep
Суть в том что теперь есть обёртка в виде Consumer. А данные из контекста передаются дальше в виде props.
TheShock
В виде каких пропс? Вы видели пример? Они передаются в виде аргументов функции-как-потомка. В пропс ничего не передается и из других методов класса контекст не получить
mayorovp
Что-то мешает взять пропсы и передать дочернему компоненту?
faiwer
Изобретаем HOC? Мешает то, что получаем ещё 1 уровень вложенности, который усложняет и debugging, и несущественно, но всё же влияет на производительность. У нас и так в сложном приложении повсюду возможны матрёшки из HOC, а так матрёшками нужно покрывать компоненты, которые используют context. Добавить к этому какие-нибудь styled-components, где матрёшкой обёрнут каждый тег со стилями, и получается, что древо компонент почти целиком состоит из композитных матрёшек. С точки зрения приложения — ок, работает же. С остальных точек зрения — спорно, очень спорно.
mayorovp
Что значит «изобретаем»? Декоратор inject в mobx-react — это уже HOC, независимо от того нравится вам это или нет.
faiwer
А я про
inject
вmobx-react
иconnect
вredux-react
и не заикался. Это изначально сильноimpure
-вещи, которые идут как большой компромисс между идеализмом и практикой. Я скорее про тотcontext
, что разработчики по своей воле сами используют в сложных проектах, устав отprops-hell
. Ниже отписал подробнее.mayorovp
Зато TheShock именно про него и говорил, а я ему отвечал.
bgnx
Используйте для HOC наследование вместо композиции и никаких новых уровней вложенности добавляться не будет
faiwer
Вы знаете, я бы с радостью. Но вот не совсем понимаю, как его тут применить. Судя по тем обрывкам, что я увидел касательно нового API, он работает именно в рамках
.render
-метода. Ну и по сути асинхронно. Не подскажите рецепт? В голову приходят только разного рода извращения, работающие с задержкой.bgnx
Да просто использовать те же хокки но только не в виде
а в виде
и все, больше никаких вложенностей и глубоких матрешек из компонентов-оберток — сколько бы хокков мы бы не навесили на компонент — да хоть тысячу — в рантайме все равно будет создан только один компонент что будет быстрее, так как вызов рендера не создаст тысячу объектов-элементов виртуального дума для этих врапперов, и реакту нужно будет выполнить diff одного компонента а не тысячи
faiwer
Вы, вероятно, имели ввиду примерно это:
Однако в данном случае мы располагаем нужным нам context-полем только внутри
super.render
. А сложные stateFull компоненты хотят его в других своих методах, включая, возможно, всякие хуки. В теории можно и это обойти, к примеру, задействовавsetState
. Но тогда мы должны писать компонент из рассчёта на двойнойrender
при инициализации, и, возможно, при одновременной смене чего-нибудь вprops
и вcontext
(но это уже редкий use case).Идём дальше. Что если нам нужно несколько полей, а не одно? Нужно городить уже достаточно сложную обвязку. Всё выполнимо, но от этого кода сильно несёт… каким-то альтернативным react-ом.
bgnx
Ну да, с новым контекстом реакта доступ возможен только внутри render-метода. То что этот контекст не будет доступен в разных хуках это проблемы нового контекста. А вообще, если нужно связывать несколько полей, то зачем нужен контекст — не лучше ли использовать внешнее состояние? Я выше привел вариант hoc-ов когда вместо композиции мы используем наследование и избегаем компонентов-оберток в рантайме что позволит улучшить производительность и каких-то минусов по сравнению композиционными hoc-ами я не вижу
faiwer
Вы имеете внешнее хранилище? Ну вот я использую redux. Но там данные приложения. А вещи которые я пробрасываю через context "руками" другого характера. Сложно объяснить. Ну кроме одной — i18n, по сути переводы и инструментарий к ним.
Да можно написать свой внешний context, по принципу того же
redux-react
-а. Но это что-то вроде из стрельбы пушки по воробьям. Серьёзное архитектурное решение.Старый context при всей своей уродливости был в чём-то изящен. Идеологически. Предполагалось, что туда помещают либо совсем что-то impure, и тогда сами ковыряйтесь в этом как хотите (react-redux скажем), либо что-то статическое, и тогда вся машинерия по re-render-у уже не нужна, а вот от килотонн бойлерплейта избавляет.
А новый контекст гораздо больше напоминает прицельные порталы для изменяемых значений. Теперь наследник окольными путями (скажем через import-export) узнаёт что-то от родителя (react в этом совсем не помогает), и позволяет от этого асинхронным образом в render методе зависеть. Вероятно, это выглядит достаточно изящно, при решении каких-то задач. Не знаю.
По поводу внешнего хранилища. Тут ещё встаёт вопрос реализации. Скажем redux-react очень уязвим в вопросе количества подписчиков. Скажем если у вас приложение рендерит сотни или тысячи мелких компонент, то подписываясь в каждом из них на store, вы заставляете connect вычислять mapStateToProps на любой чих (коих может быть очень много). В лучшем случае это просто будет жрать батарейку, в худшем ещё и тормозить.
bgnx
Ну контекст это по сути просто объект в который помечаются общие для какого-то поддерева компонентов данные. Если данные контекста не зависят от того в каком поддереве находится компонент например i18n и другие данные то мы можем просто вынести этот контекст во внешний объект в отдельном файле выполнить заимпортить этот объект и обращаться к нему напрямую. Если контекст у разных поддеревьях компонентов разный то всегда можно выразить эту сутуацию не в через компоненты а через данные.
O, вы обратились по адресу — в статьях тут, тут и тут я разбирал эту проблему и ее решение в виде mobx
faiwer
В случае MobX ? может быть. В случае redux это как-то дорого обходится.
faiwer
А старая концепция context-а, предполагала, что в нём лежат статичные данные, нечто вроде констант, которые не требуется передавать явным образом. Естественно я не имею ввиду redux и прочие динамичные штуки, а скорее какой-нибудь i18n и ему подобные вещи. Это касается в первую очередь сложных приложений, где такой подход работы с контекстном позволяет избежать много-много-многочисленных пробрасываний каких-то обобщённых props по всему большой вложенности древу вниз.
Новый же context, если я правильно понял, вполне себе динамический. Что-то вроде портала для отдельно взятых значений. Которые при этом не зазорно и менять в родительских render-ах. Получившаяся штука выходит довольно могучей, но решает она, явно какие-то другие задачи.
mayorovp
А i18n и подобные вещи — это тоже вполне себе изменяемые данные, пусть и нечасто изменяемые.
faiwer
Ок, допустим. На самом верхнем уровне, где лежит какой-нибудь
<i18n-provider/>
можно просто в случае "динамики" (например смены языка) проставить новыйkey
и, хотя мы разово перетрясём всё vdom-древо, мы добьёмся нужных результатов. При том, что на кнопку хорошо если хоть кто-нибудь нажмёт. Мне такой подход показался разумным компромиссом. А теперь же для обеспечения того же функционала, нужно (в моих проектах) покрывать HOC каждый 3-й компонент. Contex позволял обойтись малыми жертвами. А случае использования наследования давался практически бесплатно.faiwer
Хм. Отдельный момент эти сами
.consumer
-ы. Если я ничего не напутал, то их нужно передавать по ссылке. Т.е. самым явным образом. Скажем при помощиimport-export-а
, а это, в свою очередь, усложняет жизнь, не просто лишним бойлерплейтом, а ещё и тем, что если у нас один parent-component, мог порождать несколько вариаций context-значений, исходя из условий, то теперь надо будет как-то самостоятельно разграничивать их своими силами, иreact
нам в этом больше не помощник.Нет, я конечно ожидал, что
context
пересмотрят, но чтобы настолько… необычно. Этого вот я не ждал. Мне даже сложно назвать это контекстом. Скорее порталом :)TheShock
Вы понимаете зачем нужен контекст? Чтобы не пользоваться пропсами, для того, чтобы гонять по дочерним компонентам всякие вещи типа сторов. По сути, это единственный способ нормального DI в Реакте.
А вот вы мне предлагаете, если я хочу воспользоваться контекстом, чтобы не использовать пропсы — использовать пропсы? Тогда зачем вообще нужен такой костыльный контекст, если нужно просто передавать во все компоненты в пропсы еще и контекст вручную?
mayorovp
А что случилось-то? Ну делал он раньше
var additionalProps = grabStoresFn(this.context.mobxStores || {}, newProps, this.context) || {}
, а теперь будет делатьИли вы про то, что третий аргумент неоткуда взять теперь? А его вообще кто-то использует? Всегда же он был в состоянии "недодокументирован"...
TheShock
А случилось то, что раньше я мог в любом методе класса обратиться к контексту, а сейчас могу обратиться только в части метода рендер. При чем тут третий аргумент вообще?
mayorovp
Вы спрашивали как должен работать inject из mobx-react. Я ответил как.
TheShock
Всмысле «ответили»? Вы совершенно не ответили, как inject будет работать так, чтобы я мог из всех методов пользоваться зависимостями.
mayorovp
В таком случае я не понимаю как вы использовали inject до этого… Документация говорит что его надо использовать вот так:
То есть зависимости попадают в props, откуда их можно достать в любом методе.
TheShock
Вот именно что «в любом методе».
То есть я могу использовать его так:
Видите? В любом методе класса, а не только в части метода рендер.
mayorovp
Раньше inject передавал вам в props тот counter который он достал из контекста в рендере. Теперь inject будет передавать вам в props тот counter который достал Consumer в рендере.
Что поменялось-то?
TheShock
Хм, вероятно вы правы, а я — нет. Я заглядывал, но давно. Странно, мне казалось, что он иначе устроен. Последнее время менялся подход?
n0ne
Извините, конечно, может что-то не так понял, но как достучаться до this.state в getDerivedStateFromProps?! this же недоступен…
mayorovp
Он же передается вторым параметром…
n0ne
Тупикнул, спасибо (-:
faiwer
До
this.state
там дотягиваться и не нужно, т.к. он передаётся как параметр метода. А вот до всех остальных полей компонента уже по-нормальному никак. Довольно странное решение, если учесть, в документации открытым текстом сказано, что не стоит помещать в.state
поле ничего, что не участвует в.render
, мол помещайте "как есть" вthis.%property%
. Поместили. А теперь туда доступа нет :)n0ne
Да, уже понял про второй параметр, спасибо… хотя…
Как сравнить this.props и nextProps? Вернее, где теперь сравнить props, пришедшие, например, из redux??!
unel
ну, для помещения чего-то в this.%property%, я так понимаю, оставили componentDidUpdate… (если это действительно так необходимо)
faiwer
Кстати да. В большинстве не сильно хитрых случаев
componentDidUpdate
вполне сгодится. Правда вот порылся в своём коде и увидел что у меня есть методыcomponentWillReceiveProps
, которые оперируютoffsetWidth
иoffsetHeight
от<SVG/>
для формирования новогоstate
. Теперь чтобы иметь к ним доступ нужно этотDOMElement
толкать вstate
. В раздумьях. Насколько здравая идея толкать в.state
DOM-элементы, а не данные. Логика подсказывает, что ничего криминального.mayorovp
Как минимум — лишний рендер (либо WTF-логика в shouldComponentUpdate), ведь DOM-элемент можно получить только после рендера, а изменение state вызывает рендер.
faiwer
Дак и
componentWillReceiveProps
тоже вызывается уже после первогоrender
-а. А касательно того, что DOMElement раньше не получить ? что есть, то есть :) Так уж React устроен.faiwer
Интересный момент есть, связанный с
<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/>
-ы будут===
.mayorovp
Ну это как бы было очевидно…
faiwer
Мне нет. Даже в голову не пришло. Более того я уже столько материалов на эту тему нарыл, столько перечитал. Перерыл кучу обсуждений на github-е, RFC посмотрел и все доводы за и против, мотивы решения. Даже стал песочницу собирать. А потом случайно в комментариях на Medium наткнулся на вопрос про вложенность и даже ссылку на рабочий sandbox. И только поковыряв его до меня дошло, как на деле я буду его использовать (несколько вложенных instance от одного и того же Provider-а в одном древе).