Ответ на вопрос "почему" заключается в одной емкой фразе: потому что сложно синхронизировать интерфейс и состояние.
Представьте, что у вас есть простой UI какого-нибудь ToDoApp. Вам всего-то нужно сделать так, чтобы при вводе новой задачи она появлялась в списке, а при нажатии на крестик напротив удалялась бы. Проще простого!
Но когда начнете решать проблему на нативном JS или на б-гомерзком jQuery, вы столкнетесь с необходимостью писать очень много шаблонного кода. Прежде всего на обслуживание DOM. Найти элемент, вставить элемент, добавить элементу класс, атрибут... в итоге у вас получится портянка на десятки строк для такой элементарной задачи, а ведь мы еще не добавили много кульных штук, без которых ToDoApp совсем не ToDoApp, как-то: возможность создавать разные списки, расписания, галочка, чтобы зачеркивать задачу и т.п. С реализацией всего этого ваша простыня будет расти, вы будете в ней путаться.
На этом этапе вы можете начать велосипедить. Писать какие-то утилиты для работы с DOM. Разделите index.js на несколько файлов, сообразно DDD или хотя бы единой ответственности. Допустим даже, что вашим приложением внезапно стали пользоваться, у вас куча бизнес-идей. Вы начинаете наваливать фичи, структура становится все запутаннее, кода становится все больше, а еще приложение начинает тормозить. Вы проводите небольшой анализ и понимаете, что проблема в излишне частом обращении к DOM - вы дергаете его на каждый чих, ведь с jquery это так просто! И что делать? Писать еще один велосипед, чтобы обновлять DOM пакетно? А как отслеживать изменения в данных с сервера? Это ж сколько работы!
К счастью, все вышеописанное, и даже гораздо больше, уже решено в Google, Facebook, а также некоторыми талантливыми энтузиастами. И у нас есть Angular, Vue, React, Svelte, которые предлагают вам возможность создавать быстрые, поддерживаемые приложения с минимумом шаблонного кода и продуманной архитектурой.