Technically, there is no state management that does not need a BuildContext.
A widget does not exist by itself in Flutter. A Widget is accompanied by an Element. The Element maintains the position of the widget in the widget tree. If the element is mounted, then the widget is present in the widget tree. When the element is unmounted, it gets removed from the widget tree permanently. The Element contains functions like update, rebuild, performRebuild, updateChildren and many other functions that are used by the framework to manage the lifetime and under-the-hood behaviour of widgets, for updating state and for many other functionalities. You always need this Element to update the state of the corresponding Widget. Both StatelessWidget and StatefulWidget uses this element to re-render.
Surprise, surprise, the Element is actually an implementation of BuildContext as seen in framework.dart
I know that you meant using BuildContext to retrieve the object representing the state. This is more of a design choice than a technical requirement that package authors have to make. Essentially, you are using context to get the state object instance that were associated to the corresponding widget tree branch, by some parent widget. That's it. And you are doing that instead of the otherwise approach of passing around the class instance that represents state to children widgets. Both are "ok" approaches to state management.
Limiting to using the context alone is honestly in my opinion, a poor design decision. I personally believe that using context everytime to be able to incorporate state management, is just tideous. In many cases I have seen countless of apps that instantiate the Controller or ChangeNotifier only once and inject it to the root-level widget. Essentially using only one instance. One major purpose of using BuildContext is that you can provide multiple instances to multiple array of children and thereby differentiate their behaviour. But the reality is that a vast majority of apps DO NOT NEED this functionality. Another bonus of using Context is that you can retrieve object instances (of Controllers, ChangeNotifiers...) dynamically like Provider.of<MyClass>(context), without passing them around all the time. Essentially this is an example of dependency injection. But this is more of a poor design decision than great technical feat, as the source of your class instance is ambiguous. You only know the type of the instance. But ultimately, everything is personal preference, and if you are working, is often up to people who manage you to decide what architecture and state management solution to use. There are apps written using all of these "correct" approaches to state management.
You can checkout Turbo by the way. It is a very simple & efficient approach to state management I created, that does not use contexts to maintain and update state, at least not yet. It also has one of the easiest event systems so as to subscribe your widgets to only specific events.