Здесь происходит две вещи, я объясню каждую:
1. Третий аргумент для render () здесь не нужен.
Ваш компонент Counter имеет два элемента в root (<div>
и <button>
) и передает одну ссылку на элемент DOM в качестве третьего Аргумент рендеринга будет препятствовать тому, чтобы Preact использовал <button>
, существующий в «предварительно сгенерированном» DOM.
По умолчанию render(vdom, parent)
будет смотреть на всех потомков parent
и выяснять, какие они должны быть повторно использованы при подключении к существующему DOM. Существует только один очень конкретный c случай, когда это поведение не работает и третий аргумент оправдан, когда несколько «корней рендеринга» имеют один и тот же parentNode. В общем, лучше избегать такого случая, поэтому этот третий параметр не особо рекламируется в документации.
2. `htm / preact / standalone` в настоящее время, похоже, не работает
На прошлой неделе я сталкивался с подобной проблемой, так что я знал, как это проверить. По какой-то причине, когда мы встроили Preact в HTM для создания автономной сборки, он нарушил рендеринг. Вероятно, это результат чрезмерно агрессивного минимизации и должен быть исправлен в ближайшее время.
Тем временем возможно (а иногда и лучше) использовать htm
+ preact
+ preact/hooks
непосредственно из unpkg. Ключом является использование полностью разрешенных URL-адресов модулей , чтобы параметр unpkg ?module
преобразовывал импорт в те же URL-адреса, которые вы использовали для своих ручных. Вот правильные URL-адреса для вашей демонстрации:
import htm from "https://unpkg.com/htm@latest?module";
import { h, render } from "https://unpkg.com/preact@latest?module";
import { useState } from "https://unpkg.com/preact@latest/hooks/dist/hooks.module.js?module";
С удаленным третьим аргументом рендеринга и заменой импорта, ваша демонстрационная программа действительно работает нормально: ?
https://codesandbox.io/s/fast-fire-dyzhg?file= / index . html: 719-954
Бонус-раунд: Увлажнение
Моя голова сейчас очень занята в области гидратации, так что это меня очень интересует , Есть пара вещей, которые я бы порекомендовал изменить в вашем подходе, основываясь на моих исследованиях:
1. Используйте JSON для данных вместо тегов скрипта
Встроенные скрипты блокируют рендеринг и заставляют все таблицы стилей полностью загружаться перед выполнением. Это делает их непропорционально дорогими и их стоит избегать любой ценой. К счастью, решение довольно простое: вместо использования <script>__STATE__[1]={..}</script>
для данных о гидратации компонентов / сайтов вызовов переключитесь на <script type="..">
с типом mime, отличным от JavaScript. Это сделает скрипт неблокирующим, и вы сможете быстро и легко проанализировать данные как JSON при гидратации - намного быстрее, чем оценка JS, и вы сможете контролировать, когда это произойдет. Вот как это выглядит:
<div data-component="Counter">
<div>HOW MANY LIKES 0</div>
<button>Increment</button>
<script type="text/hydration-data">
{"props":{"id":1}}
</script>
</div>
Обратите внимание, что теперь вы можете использовать расположение этого тега скрипта внутри вашего компонента данных root, чтобы связать его с компонентом без необходимости использования глобальных идентификаторов.
Вот пример исправленной версии вашей демонстрации с указанным выше изменением: https://codesandbox.io/s/quirky-wildflower-29944?file= / index. html: 202-409
Надеюсь, вы найдете Обновлен корень / данные / рендер l oop для улучшения.
2. Используйте hydrate (), чтобы пропустить diff
Если вы знаете, что предварительно отрендеренная структура HTML точно соответствует исходной структуре дерева DOM, в которую ваши компоненты будут загружаться, hydrate()
позволяет вам обойти все диффинг, быстро загружаться и не касаясь DOM. Вот обновленное демо с render (), замененным на hydrate () - функциональной разницы нет, просто у него будет лучшая производительность:
https://codesandbox.io/s/thirsty-black-2uci3?file= / index. html: 1692-1709