Зависит от надобностей. Если требуется оперативно (синхронно) обрабатывать текущее значение, то вариант 1, только тем ещё нужно передавать value. Это "
управляемый компонент" - по сути, ты просто выносишь стейт из инпута наружу. Бонус: можно как-то форматировать текст на лету, либо просто вручную взять и поменять. Вариант 1 считается каноничным, потому что вынос стейта наверх - одна из базовых концепций Реакта.
Вариант 2 - изменения в одну сторону - от инпута. То есть теряется возможность управлять инпутом снаружи.
В варианте 3 обычно используют ref (забудь про id, это антиреакт). Подходит, когда тебе пофиг, что там пишется в инпуте, и надо забрать его значение (и как-то обработать) только, например, по нажатию на кнопку. Тема слегка раскрыта
здесь.
Надо отметить, что авторы Реакта пилят новую доку, и можешь почитать там философию про стейт -
https://beta.reactjs.org/learn/managing-state