Vue 2 walked an object at creation and replaced every property with a getter and setter, which meant properties added later were not reactive and array index assignment was invisible.
// Vue 2
this.state.newKey = 1; // not reactive
this.$set(this.state, 'newKey', 1);
this.items[0] = x; // not reactive
this.items.splice(0, 1, x);
// Vue 3: a Proxy intercepts everything
state.newKey = 1; // reactive
items[0] = x; // reactive
items.length = 0; // reactive
Removing $set and the array caveats is the change that most reduces the number of things a newcomer has to be told. The cost is that Proxy cannot be polyfilled, so Vue 3 does not support IE11 at all — which is a real constraint in 2020 and is the reason several projects stayed on 2.x. Collections work too, so a reactive Map is finally possible.