Conversation
e153c01 to
c10fa4e
Compare
02e5a15 to
4430c12
Compare
|
Hey there - I took a look at adding the The issue is that when you add a context-dependent component as a child of another component, we first have to render it to |
|
Not much more than you already have. Also at this point this is just an experiment, and the bigger lingering issue is how unsafe it is. I don't think I'll put much effort into it if I can't figure that detail out. |
|
Aside from the obvious danger in Context, you feel that the other hook abstractions (useState, useEffect) are more unsafe than the previous formulation? |
|
Yes, because dynamically reordering or omitting Render effects breaks the types. It probably won't work without some sort of indexing system. |
|
I would like to get it to work though :) |
|
Yes, I agree. Especially as this seems to be the direction React is headed in. But very tricky to type it safely without introducing a whole lot of machinery. |
|
I think IxMonad has made this type-safe (or if it currently has bugs they at least should be fixable). Qualified do makes using it more palatable, so hopefully that gets merged 🙂 |
|
I also added a few more examples as I've added hooks. The useRef example shows off the modularity of hooks pretty well. |
|
This is looking pretty promising - especially with qualified do. I wonder what your thoughts are on useContext though. It seems you have to track the context type of the children within the parent components and I don’t see how that is possible without refacoring the component api to make adding context-typed children explicit. |
|
Yeah... I started that and commented it back out. Alternatively it could just use the Context’s type but force it to be a Maybe when reading. |
|
The issue with Context providing a Maybe value to its children is that is basically destroys the entire semantics of using Context in the first place. I always thought of it just like a Reader monad - where we assume some context value is always provided at the top level and then just let it default to Void when none of the children require it. But then you have to track it from the children up which requires refactoring. |
|
The trouble is that it isn't one context -- it's associated with a specific Context object used for retrieval. I'm not sure how to represent that in the component types. |
|
It also sort of makes sense to build a component which can use context if it's provided, but doesn't need to. |
|
The issue with a maybe Context is that it prevents you from writing components that truly depend on a context being provided which I think is one of the major use cases. React allows multiple contexts but I think that is impossible to model, which is why in the experiments I had done I always ended up constraining the component type to require a single context object at the top level that all of the children nodes could be coerced to. The way I had constructed it prior to hooks was to provide the context to the children via props (under the hood, similar to an HOC), and then I used the props type to track it back up the chain. Even then though type inference got pretty hairy. |
|
Hmm.. only allowing a single context object seems like a bigger trade off than a Maybe, but I'll keep thinking about it. The Maybe case doesn't seem terrible for both required and optional contexts: x <- useContext requiredContext
useEffect [toKey x] do ...console warn/error if Nothing
React.pure $ case x of
Nothing -> ...warn or leave empty
Just x' -> ...normal renderx <- fromMaybe defaultContextValues <$> useContext optionalContext
React.pure $ ...normal render |
|
You may be right. I never really thought about sacrificing multiple contexts because it seemed so natural to unify them at the top level anyway into a single atom. I thought trying to get the compiler to enforce that I provided the correct context seemed a lot nicer than sniffing out runtime errors. |
[todo: a better description]
Examples: Counter, ControlledInput, others
In addition to kind of liking this api for these basic cases, I'm realizing it enables many more advanced features (action/update pattern as well as more complicated features that haven't existed before like refs and context) without complicating the basic ones.