React is based on the core concepts of encapsulated components, with the ability to manage state on a per-component-instance basis, and for parent components to pass _any_ values they want to their children as props, forming a "one-way data flow" approach.
This is _good_, because it both enables predictable behavior and React's overall rendering model.
It's _limiting_, because it means that React's own state management is inherently tree-shaped. If two widely separated components need to access the same data, you have to hoist the ownership of that state up to the nearest common ancestor, which could easily be the root `<App>` component. To put it another way, not all state is inherently tree-shaped, so there's often a mismatch.
Context is essentially "props at a distance". Put a value in a `<MyContext.Provider>` component somewhere in your tree, then any deeply nested component can read it via `useContext(MyContext)` without having to explicitly pass the value as a prop through however many intervening levels of components.
This simplifies making values accessible to that subtree, but doesn't solve the tree-vs-nontree-shaped state management question.
You _can_ build an entire app out of nothing but React component state. Plenty of folks have done it, but it's limited in what tools you have available and how you can structure things.
That's a large part of why there have been so many different state management libraries created for React, to provide alternative approaches that don't have the tree-shaped issue.
React is based on the core concepts of encapsulated components, with the ability to manage state on a per-component-instance basis, and for parent components to pass _any_ values they want to their children as props, forming a "one-way data flow" approach.
This is _good_, because it both enables predictable behavior and React's overall rendering model.
It's _limiting_, because it means that React's own state management is inherently tree-shaped. If two widely separated components need to access the same data, you have to hoist the ownership of that state up to the nearest common ancestor, which could easily be the root `<App>` component. To put it another way, not all state is inherently tree-shaped, so there's often a mismatch.
Context is essentially "props at a distance". Put a value in a `<MyContext.Provider>` component somewhere in your tree, then any deeply nested component can read it via `useContext(MyContext)` without having to explicitly pass the value as a prop through however many intervening levels of components.
This simplifies making values accessible to that subtree, but doesn't solve the tree-vs-nontree-shaped state management question.
You _can_ build an entire app out of nothing but React component state. Plenty of folks have done it, but it's limited in what tools you have available and how you can structure things.
That's a large part of why there have been so many different state management libraries created for React, to provide alternative approaches that don't have the tree-shaped issue.