The difference is mostly related to how you "configure" (or declare) things convention: what happens to something when something other happens.
In reactive programming, you declare a reaction to a change. You don't have to forsee this reaction needed to that change upfront, you may add - declare - this reaction anytime later. Therefore, it might be considered a "pull" or "watch" strategy.
Therefore, in reactive programming, you hook up to / watch data which you know that exist. Data is crucial here.
Example: a user clicked an item on the page -> update the counter how many clicks user made.
Example Calculator App: the calculator display is bound to all buttons, and reacts with any change (clicks on the buttons) with its own change on the display. Buttons don't have awareness that their clicks can be utilized by any other parts.
In event-driven programming, you trigger an event in a certain situation in the imperative-written code. You need to be explicit upfront here, because the event needs to be triggered first in order to be received later - because basically you push the event in the "change happening" part of code. So it is a "push" strategy.
Therefore, in event-driven programming, you push an event in a certain situation that maybe would be received by some other parts of code. Situation is important here, data does not matter.
Example: someone has visited the contact page -> trigger an event (which might not be received at all in the end by any listener, which is typical case for many modules and libraries).
Example Calculator App: the calculator display is just a listener, and the buttons trigger events. Buttons need to know that they exist in a certain context (but - thanks to the event-listener pattern - don't have to know what exactly is that context), and therefore they are required to trigger an event.
So in most, they are just different conventions.
Look at this simple example. The imperative approach example:
event: perform some operation on a, e.g. a += value, and trigger the event
listener: counter++
And the reactive declarative approach example:
counter: whenever an operation on a occurs, react with this: counter++
No need in the last example to trigger anything - you just "hook up" with a reaction to anything that may happen.
You may say, then, that reaction is bound to a
in reactive approach, while in imperative event-driven approach you push an event that can be later received by a listener - and since this type of approach is not related by any means to data, you may change this: a += value
to anything else later, even removing a
completely.
Event driven approach has nothing to do with data essentially. Reactive programmin is basically about data.
So as you see, reactive programming is data-oriented (change in data reacts with triggering other code), while event-driven programming is process-oriented (it doesn't matter if and what data change, if any - you just trigger an event that would be received by some other parts of code). In the latter case, you need to know that this "informing" the other parts of code is required, and you have to then foresee that the event should be triggered. In the former case, you don't have to do that, you can do it any time, or not at all - no triggering events required - but the trick here is that there must be "something" that you can hook up to with your reaction declaration, kind of watchers which allow you to react to the watched changes.