Если 1-2 уровня я бы заюзал useState на главном компоненте и прокинул пропсами, дочерние компоненты еще бы в memo обернул, чтобы не ререндера не было при изменении чего-нить другого.
Ели уже больше 2х уровней, то уж лучше положить в redux имхо, и доставать там селекторами использую useSelector. Так хотя бы данные в одном месте лежат.
Судя по подходу, который советует Дэн Абрамов с появлением хуков, уже нет как такового деления на тупые и умные компоненты, можно просто оба комопнента подконнектить к стору и обмениваться там данными.
Context использовать если это какой-то отдельный модуль со своими изолированными данными и этот отдельный модуль используется в каких то других модулях (приложениях, в случае мопонорепы например) и нет возможности его стор заюзать.