Garbage collection is less efficient, but it is sometimes very difficult to figure out exactly when a piece of memory stops being used, which leads to use-after-free, double-free and memory leak bugs.
Same goes for classical UI approaches. In classical UI, most pieces of state are kept in at least two places, once in code and at least once in the DOM.
For example, in a shopping cart, the total might appear three times, implicitly in the code (as a function that sums the prices of all the items), once as the label of the "open cart" button in the navbar, and once as text in the "your cart" modal, which that button shows or hides. THe cart may be modifiable from different places, the cart modal itself, product pages, product collection pages, order history (when re-ordering recently purchased items) etc.
In the classical approach, you need to make sure that all modifications to the cart accurately change the state in all three places. You also need to ensure that if you remove a product from the cart using the modal and you're currently on a page that lets you order the product in any way, the "remove from cart" button on that page needs to turn back into "add to cart", and there may be hundreds of different such buttons, which the cart modal needs to handle somehow. It is very easy to make mistakes here and have the state in the code (array of products) fall out of sync with what the user sees on the page.
In React, there's just one array of products, one function to calculate the total, and a lot of places in the code that use this array. WHenever the array changes, the pieces of the page that rely on it automatically re-render, while everything else stays the same. There's no way for the UI and the array to fall out of sync, and there's no need to track where the array is being used and where it's being modified.