Вышел перевод нового видео от команды hackage.tv, в котором очень доступно рассказано об использовании методов жизненного цикла в React 16.3 и getDerivedStateFromProps в частности.


Комментарии (12)


  1. friday
    12.04.2018 11:49

    Стенограммы нет?


    1. maxfarseer Автор
      12.04.2018 11:52

      Увы. Можете помочь, обновлю публикацию.
      p.s. большую часть видео идет речь только про getDerivedStateFromProps. Само видео короткое (9 мин)


  1. Gentlee
    12.04.2018 12:05

    То есть эти гении не додумались передавать prevProps (nullable) в этот метод и поэтому нужно дублировать prop в state? Ещё и не рассказано в какой момент вызывается этот метод.


    1. justboris
      13.04.2018 00:03

      Если ваш вопрос не троллинг, то вы можете найти ответ на него в этой ветке обсуждения на github:
      https://github.com/reactjs/rfcs/pull/6#discussion_r162865372


      Когда вызывается метод, можно увидеть на этой диаграмме:
      https://mobile.twitter.com/dan_abramov/status/981712092611989509


      1. faiwer
        13.04.2018 08:03

        Не совсем понятно почему мы в том методе изолированы от prevProps и вынуждены прибегать к такому грязному костылю с дубляжом полей (да ещё и насильно делая компонент statefull "просто так"). Там случаем нигде не проскальзывало внятное объяснение причин?


        Честно говоря у меня много вопросов к 16.1+. Скажем я так и не понял как получить доступ к context полю в рядовых методах компонента (а не только в render). Ничего умнее:


        render()
        {
          return <Consumer>{some =>
          {
            this.someFromContext = some; // <= dirty trick
            return /* any jsx */;
          }</Consumer/>;
        }

        Случаем нигде не проскакивал reactWay по такому случаю?


        1. Odrin
          13.04.2018 09:44

          function as a child — довольно распространенный подход (react-router, react-motion и т.д.), а сам Consumer предполагается использовать как-то так:

          <Consumer>
            {
              data => (
                <MyComponent data={data} />
              )
            }
          </Consumer>
          

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


          1. faiwer
            13.04.2018 09:49

            HOC это дополнительный уровень иерархии и это не бесплатно. <Consumer/> уже сам по себе создаёт 1 уровень (React Dev Tools его видит). С HOC их будет уже два. Открыл я свой проект и ужаснулся. На несколько DIV-ов гора обёрток над обёртками над обёртками. Впору уже делать доп. поле (помимо displayName), чтобы можно было скрывать всю эту шелуху.


            function as a child — довольно распространенный подход

            Ну и что? Это же просто неудобно для statefull компонент.


            1. Odrin
              13.04.2018 10:33
              +1

              Вы хотели react way, я вам его дал. И делать именно так гораздо лучше, чем использовать этот костыль с «this.someFromContext = some».

              HOC это дополнительный уровень иерархии и это не бесплатно
              Любая строчка кода — это не бесплатно. Конкретно в нашем случае цена стремиться к нулю и я не представляю, какая должна быть вложенность (тысячи HOC?), что бы заметить хоть какое-то влияние на производительность. И уж точно это никогда не станет bottleneck, потому что он всегда будет в работе с DOM.
              На несколько DIV-ов гора обёрток над обёртками над обёртками
              Тут скорее проблема в средствах отладки, которые не позволяют все это дело отобразить в удобном виде, а не в самом подходе. Вы же понимаете, что если бы не было оберток, то был бы один раздутый компонент. Как мне кажется, это гораздо хуже.
              Это же просто неудобно для statefull компонент
              Можете привести пример, где это неудобно? За все время использования React не сталкивался с какими-то неудобствами этого подхода, даже наоборот.


              1. faiwer
                13.04.2018 11:04

                потому что он всегда будет в работе с DOM

                Это не правда. DOM далеко не всегда является главным тормозом. Неудачная архитектура и бездумное использование фреймворка может заткнуть за пояс тормоза DOM-а. Я регулярно с этим сталкиваюсь в различных сторонних SPA. Минимальные изменения DOM заставляют куллер на CPU гудеть а мозг ждать.


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


                В случае Redux достаточно наплодить subscribe-ов (например квадратично — ячейки таблицы). И тогда CPU только и будет делать, что считать mapStateToProps и mapDispathToProps. А если их ещё и не мемоизировать, то оно умрёт в адских корчах ещё при рождении.


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

                Вместо кучи обёрток был бы 1 быстро и эффективно работающий компонент. По правде говоря, на мой вкус, такие вещи вообще должны быть зарыты внутри самого React, где можно избежать массы бесполезных стадий. И вот это было бы гораздо лучше.


                Если мы говорим о большом react+redux приложении со сложной историей, большой произвольной вложенностью, изобилием DOM, то при небольших ошибках с его архитектурой мы легко получаем весьма посредственную производительность. И если начать копать, то получается, что браузер только и делает, что тасует всякие { ...this.props, ...some.mix }. А потом сравнивает горы VDom между собой.


              1. faiwer
                13.04.2018 11:09

                Можете привести пример, где это неудобно?

                Код
                // before
                
                handle = () =>
                {
                    const { i18n } = this.context;
                    if(confirm(i18n('Are you sure?')))
                        this.props.remove();
                }
                
                render()
                {
                    return <some onClick={this.handle}>del</some>;
                }
                
                // after
                
                render()
                {
                    return <Consumer>i18n =>
                    {
                        this.i18n = i18n;
                        <some onClick={this.handle}>del</some>
                    }</Consumer>
                }
                
                // or 
                
                I18nHoC(Component)


        1. justboris
          13.04.2018 11:06

          Не совсем понятно почему мы в том методе изолированы от prevProps и вынуждены прибегать к такому грязному костылю с дубляжом полей Там случаем нигде не проскальзывало внятное объяснение причин?

          Если у вас не получилось перейти по ссылке и почитать, то вот вам скриншоты оттуда


          Раз


          1. faiwer
            13.04.2018 11:18

            Если у вас не получилось перейти по ссылке и почитать, то вот вам скриншоты оттуда

            Вы знаете, у меня и сейчас не получается. Может ссылка кривая. Даже поиск по странице по словам из скриншотов ничего не находит. Впрочем не важно, спасибо за скриншоты. Ребята предлагают костыль с setState во избежание проверки на null (TypeScript и все дела). Возможно это и правда имеет смысл. Лично я просто воткнул бы в качестве prevProps текущий props при инициализации и описал бы это в документации. Это тоже своего рода костыль. Но на мой вкус куда менее убогий текущего решения.