The concept of "Context" is used a lot in software engineering. One good principle of software engineering is that we should always build small independent testable components and then use them like building blocks. Sort of lego bricks that can be reused. This is a very good principle but in real life, the use of a software component often depends on the larger picture. For example in lego, you might want to use a red brick next to another red brick instead of mis-matching colors. Hence even though a lego brick is fully independent piece, its correct use might depend on the context of what you are building such as color of rest of the bricks.
For react this has been a long standing problem. React is designed specifically to create your UI using composable set of independent components and yet, these components need to remember the context in which they appear. For example a button component might depend on the theme that the user has picked.
Historically this was solved using prop-drilling where each component gets the "context" from its parent. This makes sense. In the lego analogy you look at the color of adjacent brick only to select the next brick. It works for smaller projects. But as you try to build something really big, it is not enough to just look at the next brick but rather you need to look at the whole picture.
This was solved by third party libraries like "Redux". These libraries basically create a shared "store" to which a lot of components and read and write.
But this basically makes things complicated as it completely violates the "independent" component idea and now all your components depend on a certain shared store state.
There is no proper elegant solution to this catch-22 situation.
Context API can be seen as a lightweight solution to the shared state problem but it does not eliminate the problem. In React's Context api a top level react component is responsible for creating an object which it thinks its children need to use. It then "provides" that object. Once the parent component has done its job, the children components can automatically get it by simply calling "useContext" API.
This solution differs from Redux because Redux often relies on a massive large single store. But Context api relies on many small independent context objects. When you are modifying a Redux store you might have to worry too much about how the store is structured. With context API you don't have to concern yourself with other contexts at all.
Conclusion
Using context API is a good compromise between massive prop drilling and overly complicated Redux store. In all these cases the health of your code will eventually depend on how you minimize their usages entirely and how well you design them. It is an art and not science.
References:
[1] https://www.frontendeng.dev/blog/51-react-inter-component-communication-through-context