Try MobX. I think it's the holy grail of state management.
You have your app state in an object/class, and components automatically rerender when the part of the store changes that they access during render.
class Store {
counter = 0
constructor() { makeAutoObservable(this) }
increment() { this.counter++ }
}
const Component = observer(() {
const store = useStore()
const click = () => store.increment())
return <button onClick={click}>{store.counter}</button>
})
It has a very light set of idiosyncrasies for what it gives you unlike, say, redux.