V4Fire / Client

V4Fire client core library
MIT License
23 stars 15 forks source link

Теряется ref для компонентов размещенных в слотах внутри async render #1090

Open shining-mind opened 9 months ago

shining-mind commented 9 months ago
  1. Переключиться на ветку issues/1090
  2. Собрать проект npx webpack --watch --env public-path=//
  3. Запустить веб сервер npx static ./dist/client
  4. Перейти по ссылке http://127.0.0.1:8080/p-v4-components-demo.html и открыть консоль:
select ref {$root: {…}, $parent: {…}, $normalParent: {…}, …}
dummy ref {$root: {…}, $parent: {…}, $normalParent: {…}, …}
async select ref undefined
async dummy ref [{…}]

На селект, размещенный в слоте default компонента b-dummy, нет рефа.

Если компонент сделать функциональным, то рефы появляются, это связано с тем, что у vnode функциональных компонентов есть проп ref и свойство ref:

image

У обычных компонентов свойство ref не задано:

image
shining-mind commented 9 months ago

В итоге реф selectAsync:u11b99ae2e0e3b2 записывается в $refs к b-dummy, который создан внутри async render. Потому в root компоненте не получается его зарезолвить.

Причина в следующем: внутри async render withCtx теряет ссылку на контекст (currentRenderingInstance), потому слоты создаются с ссылкой на инстанс компонента в рамках которого они вставлены.

Чтобы полечить эту проблему необходимо кэшировать currentRenderingInstance, т.е. завернуть коллбэк функцию для renderList в некое подобие withCtx.

shining-mind commented 9 months ago

Fixed in #1091

shining-mind commented 2 days ago

Фикс в #1091 сломался в версии Vue 3.4.7. Ломается обычный v-for, из-за того что мы привязываем currentRenderingInstance внутри renderList.

Сейчас проблему решили иначе: #1487. Сделали так, чтобы v-ref всегда был пропсом.

У нас остается по прежнему две проблемы в случае асинк рендера:

  1. Фикс не будет работать для кейсов с v-func = someExpression
  2. Корневые узлы компонентов имеют ref = null, так как потерян контекст currentRenderingInstance (ломает ли это что-то на практике не известно, но это отличается от синхронного рендера).