Недавно в Nuggets был успешно запущен мой первый буклет «React Hooks и Immutable Dataflow на практике». Дорогие фанаты и друзья, я ждал долго. План двухмесячной давности откладывается до сих пор, и я часто чувствую всеобщее беспокойство в проблемной области GitHub. Мне очень жаль, но, к счастью, это наконец удачно вышел..
Он был в сети менее 5 дней, и без каких-либо твитов объем продаж превысил 400. Это то, чего я никогда не ожидал, но это также отражает доверие моих друзей ко мне. Я взглянул на список идентификаторов на заднем плане, там много знакомых лиц, но больше почти невпечатляющих или даже совершенно незнакомых идентификаторов.Действительно, оглядываясь назад на рост Nuggets в эти дни,写作
,思考
и挣扎
Процессчрезвычайно болезненныйДа, но именно потому, что вы случайно наткнулись на статью点了赞
, дал немного反馈
, так что у меня хватит боевого духа и упорства, чтобы выстоять. Может быть, мы никогда не встречались, и у нас даже нет WeChat, но в месте под названием «Наггетс» я получил признание от незнакомца.Такого чувства никогда не было раньше, и оно всегда вдохновляло меня продолжать придерживаться мотивация. Ждёте ли вы эту долгожданную или случайно открываете эту статью, позвольте мне сказать очень искренне:Большое спасибо!
Возвращаясь к самому буклету, к исследованию присоединились многие мелкие партнеры. Тем не менее, я считал необходимым официально представить брошюру, так как чувствовал, что это моя ответственность как автора брошюры.
источник
Буклет сам по себе является учебным пособием по проекту, так почему же я хочу заниматься таким проектом?
На самом деле это довольно забавно, я просто хочу сделать деликатный проект. Вспомните знаменитых преподавателей МООК七月
Я как-то сказал: технология на самом деле очень чистая, в конце концов, это не более чем два пункта: один — работать, чтобы зарабатывать деньги, а другой — делать то, что ты хочешь делать. И то, что я сделал позже, лишь подтвердило последнее. Во многих случаях достичь 60 баллов относительно легко и доступно обычным людям. Однако для достижения 90 баллов или даже выше часто требуется чрезвычайно тяжелая работа и даже требуются соответствующие возможности и таланты. Это также причина, по которой в Интернете так много проектов с похожей тематикой, и я все еще настаиваю на этом проекте. Я хочу сделать проект самостоятельно, он должен быть достаточно доработанным, и это не для кого-то.
Затем я попытался интегрировать знания, которые я получил некоторое время назад, и я планирую использоватьReact
соответствоватьImmutable
(Неизменяемые) данные и используйте самый популярный мир Reacthooks
служить базовым стеком технологий для всего проекта.
Зачем использовать крючки?
Я хочу сказать, что теперь React Hooks можно назвать "популярной нишей" в мире фронтенда. Из-за простоты API и повторного использования логики он постепенно используется разработчиками. Vue3.0 также принимает аналогичную функцию. На основе модели, поэтому изучение React Hooks также является большой тенденцией в будущем. Я не хочу повторяться здесь都xxx年了,再不学xxx就要被淘汰了
С точки зрения продажи беспокойства, на самом деле нет технологии, которую нужно изучать.Если она достаточно хороша, я готов поделиться ею с вами, чтобы больше людей могли наслаждаться удобством и повышением эффективности, которые она приносит. заhooks
Как игрок, который использовал его в деталях, я думаю, что очень рад поделиться им с вами. Чтобы попрактиковаться и применить функцию хуков в конкретном проекте, я думаю, что это намного сильнее, чем сухая документация, и в процессе практики будут некоторые ямки.Изучение пит-драйва может углубить наше понимание принципа хуков.
Зачем использовать неизменяемые данные?
Это сложнее. Я думаю, что я должен сначала представить механизм рендеринга React — процесс согласования (многие переводят его как «последовательный процесс обработки», лично я считаю это не очень уместным, и лучше дословно переводить как «согласование», и смотрите расшифровку ниже).
механизм рендеринга
Как показано на рисунке выше, React использует виртуальный DOM (то есть VDOM).Каждый раз, когда изменяются свойства (реквизиты) и состояние (состояние), функция рендеринга возвращает другое дерево элементов, и React обнаружит текущее возвращенное дерево элементов и Предыдущее дерево элементов.Разница перед деревом элементов второго рендеринга, затем для разницы выполняется операция обновления, и наконец рендерится настоящий DOM.Это и есть весь процесс Реконсилации, ядром которого является алгоритм diff который сравнивает старое и новое деревья DOM.
Для того, чтобы получить лучшую производительность, первое, что нужно сделать, это减少 diff 的过程
, тогда, исходя из того, что узлы, которые должны быть обновлены, могут быть обновлены, как избежать этого процесса сравнения?
Ответ заключается в использовании функции цикла объявления shouldComponentUpdate. Что делает эта функция?
По умолчанию shouldComponentUpdate вернет true при изменении свойств и состояния, указывая на то, что компонент будет повторно визуализирован, таким образом, вызывая функцию рендеринга для выполнения сравнения различий между новым и старым деревьями DOM. Но мы можем сделать некоторые суждения в этой функции жизненного цикла, а затем вернуть логическое значение и вернуть true, чтобы указать, что текущий компонент будет обновлен, и false, чтобы не обновлять текущий компонент. Другими словами, мы можем контролировать, происходит ли процесс сравнения дерева VDOM через shouldComponentUpdate.
Ключевые точки знаний были изложены. Теперь давайте возьмем в качестве примера официальную диаграмму React, чтобы полностью проанализировать процесс примирения:
SCU I.E. SCU I.E. SCUPONENTUPDATE CONDOWNH FIGN красные узлы представляют собой функцию Figcomponentupdate True, вызовите метод рендеринга, Diff Vdom Old до нового дерева, зеленые узлы представляют собой функцию возвращается FALSE, не нужно обновлять дерево DOM.
Начиная с C1, C1 является красным узлом, shouldComponentUpdate возвращает true, и требуется дальнейшее сравнение старого и нового деревьев VDOM, предполагая, что C1 на двух деревьях теперь节点类型相同
, затем рекурсивно введите сравнение следующего слоя узлов, сначала введите C2, зеленый узел, указывающий, что SCU возвращает false,不需要对 C2 的 VDOM 节点进行比对
,в то же времяC2 下面所有的后代节点
Не надо сравнивать.
Теперь введите C3, C3 — красный узел, указывающий, что SCU верен, и необходимо выполнить сравнение на этом узле, предполагая, что два дерева имеютC3 节点类型相同
, затем продолжайте вводить следующий уровень сравнения. В r C6 — красный узел, и выполняется соответствующая операция diff.И C7, и C8 — зеленые узлы, и их не нужно обновлять.
Конечно, у вас могут возникнуть сомнения, вышеприведенное предполагает, что типы узлов одинаковы при дифференциации, что, если типы узлов не совпадают? Подход React здесь очень простой и грубый, прямо原 VDOM 树上该节点以及该节点下所有的后代节点
Удалите их все, а затем замените их узлами в той же позиции в новом дереве VDOM, конечно, все узлы-потомки этого узла следуют. Это относится к деталям реализации алгоритма diff, разбирать diff более полно и подробно мы будем в пасхалке в конце статьи :)
Таким образом, мы можем обнаружить, что если мы сможем разумно использовать shouldComponentUpdate, мы сможем избежать ненужного процесса согласования и повысить производительность приложения.
Как правило, shouldComponentUpdate сравнивает, изменились ли свойства свойств и состояния (поверхностное сравнение), чтобы определить, следует ли возвращать значение true, тем самым запуская процесс согласования. Типичным приложением является API PureComponent, представленный в React, который неглубоко сравнивает данные двух компонентов при изменении свойств или состояния.
Но этот проект полностью охватывает функциональные компоненты и больше не использует компоненты класса, поэтому shouldComponentUpdate больше нельзя использовать. После использования функциональных компонентов нет ли решения для поверхностного сравнения? Не совсем. React предоставляет функциональный компонентmemo
метод, единственная разница между ним и PureComponent в сравнении данных заключается в том, что只进行了 props 的浅比较
, потому что компоненты функции не имеют состояния. И его использование очень простое, просто передайте функцию прямо в memo и экспортируйте ее. В форме:
function Home () {
//xxx
}
export default memo (Home);
Это также объясняет, почему нам нужно добавлять пакет memo при экспорте каждого компонента.
Теперь есть ряд схем оптимизации.
Схема оптимизации 1: PureComponent (памятка) для неглубокого сравнения
В предыдущем разделе я заложил предзнаменование того, что PureComponent или memo будут выполнять поверхностное сравнение старых и новых данных. Вам может быть более любопытно, как сравнивается поверхностное сравнение? Я думаю, что более важно, чтобы все чувствовали интуитивно, поэтому я возьму основной исходный код части поверхностного сравнения PureComponent, чтобы все могли ее испытать.Не нервничайте, логика на самом деле очень проста.
function shallowEqual (objA: mixed, objB: mixed): boolean {
// 下面的 is 相当于 === 的功能,只是对 + 0 和 - 0,以及 NaN 和 NaN 的情况进行了特殊处理
// 第一关:基础数据类型直接比较出结果
if (is (objA, objB)) {
return true;
}
// 第二关:只要有一个不是对象数据类型就返回 false
if (
typeof objA !== 'object' ||
objA === null ||
typeof objB !== 'object' ||
objB === null
) {
return false;
}
// 第三关:在这里已经可以保证两个都是对象数据类型,比较两者的属性数量
const keysA = Object.keys (objA);
const keysB = Object.keys (objB);
if (keysA.length !== keysB.length) {
return false;
}
// 第四关:比较两者的属性是否相等,值是否相等
for (let i = 0; i < keysA.length; i++) {
if (
!hasOwnProperty.call (objB, keysA [i]) ||
!is (objA [keysA [i]], objB [keysA [i]])
) {
return false;
}
}
return true;
}
Как видно из написанных мной заметок, здесь открыто четыре уровня, но все же это поверхностное сравнение. В следующих случаях будет судить отказ.
state: {a: ["1"]} -> state: {a: ["1", "2"]}
На самом деле массив изменился, но поверхностное сравнение показало бы отсутствие изменений, потому что ссылка на массив не изменилась. Вы видите это? Поверхностное сравнение прекращается, когда значение свойства является ссылочным типом.
Это самый большой недостаток этого метода.Из-за присвоения ссылок JS этот метод подходит только для компонентов без состояния или компонентов с очень простыми данными состояния.Для большого количества компонентов приложения он бессилен.
План оптимизации 2: глубокое сравнение в shouldComponentUpdate
Чтобы решить проблему, которую принесло первое решение, мы сейчас не будем делать поверхностное сравнение, а рекурсивно сравним все свойства и значения в реквизитах.
Давайте внесем некоторые волшебные изменения в код для неглубокого сравнения выше:
function deepEqual (objA: mixed, objB: mixed): boolean {
// 下面的 is 相当于 === 的功能,只是对 + 0 和 - 0,以及 NaN 和 NaN 的情况进行了特殊处理
// 第一关:保证两者都是基本数据类型。基础数据类型直接比较出结果。
// 对象类型咱就不比了
if (objA == null && objB == null) return true;
if (typeof objA !== 'object' &&
typeof objB !== 'object' &&
is (objA, objB)) {
return true;
}
// 第二关:只要有一个不是对象数据类型就返回 false
if (
typeof objA !== 'object' ||
objA === null ||
typeof objB !== 'object' ||
objB === null
) {
return false;
}
// 第三关:在这里已经可以保证两个都是对象数据类型,比较两者的属性数量
const keysA = Object.keys (objA);
const keysB = Object.keys (objB);
if (keysA.length !== keysB.length) {
return false;
}
// 第四关:比较两者的属性是否相等,值是否相等
for (let i = 0; i < keysA.length; i++) {
if (
!hasOwnProperty.call (objB, keysA [i]) ||
!is (objA [keysA [i]], objB [keysA [i]])
) {
return false;
} else {
if (!deepEqual (objA [keysA [i]], objB [keysA [i]])){
return false;
}
}
}
return true;
}
При доступе к значению атрибута объекта значение атрибута рекурсивно сравнивается, таким образом достигается эффект глубокого сравнения. Но подумайте о экстремальной ситуации, то есть когда есть 10 000 атрибутов, изменился только последний атрибут, тогда нам нужно пройти все 10 000 атрибутов. Это очень расточительно для производительности.
Оптимизация 3: неизменяемая структура данных + поверхностное выравнивание SCU (memo)
Вернемся к сути проблемы: независимо от того, используем ли мы поверхностное сравнение напрямую или выполняем глубокое сравнение, в конечном счете мы хотим знать, изменились ли реквизиты (или состояние) данных компонента.
В таких условиях возникли неизменяемые данные.
Что такое неизменяемые данные? Какие у него есть преимущества?
неизменяемые данные — это постоянная структура данных, сформированная с использованием совместного использования структуры.После изменения части будет возвращен совершенно новый объект, а исходный тот же узел будет напрямую передан.
В частности, данные неизменяемого объекта имеют внутреннюю структуру с несколькими деревьями.Каждый раз, когда узел изменяется, он и все связанные с ним вышестоящие узлы обновляются.
Используйте движущееся изображение, чтобы имитировать этот процесс:
правильно! Обновляется только родительский узел, что намного лучше, чем прямое сравнение всех атрибутов, и после того, как обновление возвращает совершенно новую ссылку, даже поверхностное сравнение может обнаружить изменение данных.Таким образом, использование immutable может не только обновлять структуру данных с максимальной эффективностью, но и плавно подключаться к существующему PureComponent (памятке) и воспринимать изменение состояния, что является отличным решением для повышения производительности рендеринга React.
Но есть одна вещь, чтобы сказать, неизменяемость также имеет некоторые моменты, на которые жалуются некоторые разработчики.Прежде всего, неизменяемые объекты и объекты JS должны быть преобразованы, а не смешаны.Каждый должен обратить внимание на обращение к toJS или fromJS, когда это уместно, и проблема не большой.
Во-вторых, разногласия по поводу стоимости обучения неизменяемого API. Я думаю, что этот вопрос является вопросом мнения.Моя точка зрения такова: если вы в настоящее время балуетесь технологическим стеком, который использовался очень умело, не говоря уже о глубоком изучении новых технологий, даже новые API слишком ленивы, чтобы учиться, я думаю, это для личного роста.Плохой знак.
цель обучения
Подсчитано, что некоторые учащиеся не удовлетворены прочитанным выше и спрашивают: «Какой смысл учить это?»
- Опыт использования React Hooks для развития бизнеса, понимание возникающих сценариев
闭包陷阱
, как избежать подводных камней. - почерк рядом
6000行代码
, упаковка13
основные компоненты пользовательского интерфейса,12
Бизнес-компонент, досконально освоить весь процесс инженерного кодирования React + Redux. - Инкапсулируйте часто используемые мобильные компоненты для достижения общих требований, таких как
封装滚动组件
,实现图片懒加载
,实现上拉/下拉刷新
функция,实现防抖
Функции,实现组件代码分割
(Разделение кода) и т. д. - Иметь практический проектный опыт реализации сложных интерфейсных взаимодействий, улучшать собственныевнутренняя сила, такие как разработка ядра плеера, является одной из самых больших проблем.
- Овладейте многими навыками в CSS, улучшите свои навыки CSS, независимо от макета или анимации, есть много практики и исследований,Не использовать какой-либо UI-фреймворк, код стиля реализуется самостоятельно.
- понять доскональнопринцип редукции, и может самостоятельно разрабатывать промежуточное ПО Redux.
Брошюра Перспективы
После запуска буклета я также слышал один за другим отзывы от коллег-диггеров: кто-то вносил опечатки в статью, кто-то предлагал правки в код проекта, активное участие каждого из которых не позволяло мне расслабляться. Обновление и сопровождение проекта еще в процессе.В дальнейшем по результатам общения с вами будут реконструированы некоторые детали проекта и добавлены еще пасхалки.Текущий план-hooks
Серия статей по анализу исходного кода размещена в буклете, что постоянно повышает ценность буклета. Я надеюсь, что вы можете оказать большую поддержку, и я надеюсь, что вы сможете получить достаточно упражнений и получить достаточный опыт в рамках этого проекта. Более подробная информация о проекте не будет повторяться здесь. В первом разделе буклета достаточно конкретных вводных слов. . . .
наконец служитьадрес буклета, Удачного обучения!