Can someone point me to reasonably simple but not contrived examples that put createContext and forwardRef to good use? As I look at this from a Mithril perspective the value isn't obvious.
Context is a way to pass state down the component tree without it having to go through intermediate nodes.
Say context doesn't exist, and you have a branch of components A -> B -> C, if C depends on some state in A, B would have to have a dependency on that state too. And you'd need some boilerplate code in B that reads the props from A, and passes them to C.
If you want to use C in a different context, say A -> D -> C, then that boilerplate code needs to exist in D as well.
With larger apps, containing large component trees, the amount of this boilerplate prop-passing you need to do starts to get excessive. It's not uncommon to see components read 14 props from their parent, use one of them, and pass 13 to their child(ren).
Until now, this problem has been solved by using data stores that inject state anywhere in the tree that they please. Context is an alternative to that.
It's always existed, just now it has a new API. I have no idea what was wrong with the old one. Nobody seems to have properly explained it anywhere, the docs just make condescending suggestions not to use it without reasoning. I think I saw an arcane tweet once explaining that certain things may not have re-rendered properly when using the old API or something...
I still think I'll need examples to be convinced of the usefulness, though. I don't see why a large component tree would have 14 disparate props passed down individually. If the tree is supposed to be a reusable component, why not define a single object to pass down?
Edit: Having read the docs I now see that my current perspective on it is the one they want me to have. "Don’t use context just to avoid passing props a few levels down. Stick to cases where the same data needs to accessed in many components at multiple levels." So it's better for me to avoid it until I see it's definitely needed.
I'm curious why the theme example I mentioned in my earlier comment- (and showed in the docs)- doesn't qualify as "useful" to you. Another example would be using context to share the selected language/locale between all of the localized components in an application.
In self-contained apps couldn't a single prop be passed down that's an object with all things like that in it? Maybe there's a scenario with 3rd-party components where context could make it look more elegant, but I don't have a clear picture.
I know there are several ways to construct a component, but I like that your examples make them functions of props, because that's how I picture a component. Having its behavior depend on a semi-hidden context appears less purely functional. To stretch the term a little, the component is no longer idempotent. Maybe there's a situation where that's what you want, but the examples you've given so far sound like ones where props would serve just fine.
OK, it just boils down to me thinking one explicit prop for every component isn't too much boilerplate. I can see some teams liking the idea of shaving off that explicit prop as long as everybody knows about the implicit context(s) that also affect component behavior.
In my experience, examples are only useful if they have two points of comparison side by side.
For example if I'm looking into a new library that claims to simplify my app's architecture or reduce boilerplate, I need to see what the alternative would look like for a given example, otherwise it's just a baseless claim.
Same as things that purportedly "scale". Since every library under the sun claims that as a benefit, I wouldn't even bother recommending any of them to anyone on here without an example of a large app both with and without the library, pointing out the specific sections of code that change for the better.
- It was a single shared key/value namespace, which could potentially lead to different libraries attempting to put values at the same key and stomping on each other
- It was fine for passing down _initial_ values, but if you tried to _update_ a value, any components that returned `false` from `shouldComponentUpdate` would block their descendants from receiving the updated context values
AFAIK the problem with the old context is that values in context were not used to determine whether or not the component tree should update. So if a context value in A changed, but no props/local state changed, it would not redraw the tree below it (B -> C). If C's render depended on the context value, it would not be redrawn to reflect the change.
Say context doesn't exist, and you have a branch of components A -> B -> C, if C depends on some state in A, B would have to have a dependency on that state too. And you'd need some boilerplate code in B that reads the props from A, and passes them to C.
If you want to use C in a different context, say A -> D -> C, then that boilerplate code needs to exist in D as well.
With larger apps, containing large component trees, the amount of this boilerplate prop-passing you need to do starts to get excessive. It's not uncommon to see components read 14 props from their parent, use one of them, and pass 13 to their child(ren).
Until now, this problem has been solved by using data stores that inject state anywhere in the tree that they please. Context is an alternative to that.
It's always existed, just now it has a new API. I have no idea what was wrong with the old one. Nobody seems to have properly explained it anywhere, the docs just make condescending suggestions not to use it without reasoning. I think I saw an arcane tweet once explaining that certain things may not have re-rendered properly when using the old API or something...