To react to buffer changes, you generally want to use after-change-functions (or sometimes before-change-functions).
These hooks are run everytime some part of the buffer is modified, either by inserting or by deleting a chunk of text (or text-properties). Be aware that some commands work by applying several modifications to the buffer, so those hooks can be run several (or even many) times in a single command. So if you need to perform a a significant amount of work, it is often useful to use 2-step approach, where an after-change-function only keeps track of the affected region, and then a post-command-hook uses that data to perform the heavy lifting.
E.g.
(defvar foo-unhandled-changes nil) (defun foo-after-change-function (beg end _len) "Remember to fixup the text between BEG and END." (unless undo-in-progress (if foo-unhandled-changes (setq foo-unhandled-changes (cons (min beg (car foo-unhandled-changes)) (max end (cdr foo-unhandled-changes)))) (setq foo-unhandled-changes (cons beg end)))))
then use (add-hook 'after-change-functions #'foo-after-change-function nil t) where needed, plus a post-command-hook which can use foo-unhandled-changes to know which part of the buffer (if any) was modified since last time it was run (and which should reset foo-unhandled-changes to nil).
point): better make a separate question for that.