В чем разница shallowRef и ref во Vue
Что проверяют
Понимаете ли вы, что реактивность бывает глубокой, и знаете ли, зачем от неё иногда отказываются.
Как отвечать
ref создаёт глубоко реактивную ссылку: если внутри объект, он рекурсивно оборачивается в reactive, и отслеживается изменение любого вложенного свойства.
shallowRef реактивен только на замену .value целиком. Внутренности не оборачиваются, и изменение вложенного поля не вызовет обновления.
const deep = ref({ a: 1 });
deep.value.a = 2; // обновление произойдёт
const shallow = shallowRef({ a: 1 });
shallow.value.a = 2; // ничего не произойдёт
shallow.value = { a: 2 }; // а вот так даЗачем отказываться от глубокой реактивности:
- производительность на больших структурах: обёртка через прокси стоит времени и памяти. Массив из десятков тысяч элементов или дерево большой вложенности выгоднее держать в
shallowRefи заменять целиком; - внешние объекты: экземпляр карты, редактора, графика, соединение. Оборачивать их в прокси не только бесполезно, но и вредно: библиотека может сломаться, потому что сравнивает объекты по ссылке или хранит внутреннее состояние;
- неизменяемые данные: если вы всё равно заменяете значение целиком, глубокая реактивность лишняя.
Полезные дополнения: triggerRef заставляет обновиться вручную, если вы изменили внутренности shallowRef осознанно, а markRaw помечает объект как нереактивный навсегда, что удобно для тех же сторонних экземпляров. Есть и парный shallowReactive.
Главная ошибка на практике: взять shallowRef ради скорости и продолжить менять вложенные поля, ожидая обновления интерфейса. Правило простое: с shallowRef данные заменяются целиком.
Где спотыкаются
Мутируют вложенное поле shallowRef и не понимают, почему экран не обновился.
Оборачивают в ref экземпляр сторонней библиотеки и ломают её.
Не знают про triggerRef и markRaw.
Считают shallowRef просто оптимизацией без изменения поведения.