-
Notifications
You must be signed in to change notification settings - Fork 40
Add support for React Context #101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, thanks! Looks pretty close -- I've add a couple notes
src/React/Basic.purs
Outdated
-- | ``` | ||
-- | | ||
-- | __*See also:* `provider`, `consumer`, React's documentation regarding Context__ | ||
foreign import createContext :: forall a. a -> ReactContext a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should have the type EffectFn1 a (ReactContext a)
. I know we've cheated in other places but we're working to get away from that 😅. Probably best to name this createContext_
, hidden, and export createContext = runEffectFn1 createContext_
instead. Alternatively the FFI could be curried manually and this could just have the type a -> Effect (ReactContext a)
Actually, I've been thinking about it a bit more and I think it'd be a good idea to preserve the React context object (the exact one returned from foreign import data ReactContext :: Type -> Type
foreign import contextProvider :: forall a. ReactContext a -> a -> Array JSX -> JSX
foreign import contextConsumer :: forall a. ReactContext a -> (a -> Array JSX) -> JSX This would allow the |
If we follow foreign import data ReactContext :: Type -> Type And we've used up foreign import contextProviderReactComponent :: forall a. ReactContext a -> ReactComponent { value :: a, children :: Array JSX } Or might it be better we just declare, and use the ff directly without changing the names: type ReactContext a =
{ "Provider": ReactComponent { value :: a, children :: Array JSX }
, "Consumer": ReactComponent { children :: a -> Array JSX }
} |
I don’t think I’d do either. The two functions are the accessors. They could return the |
I've changed ReactContext to be a foreign type and effectful, then added the accessors. But I retained the existing |
e9f77d7
to
24de5ef
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great, thank you!
-- | render self = | ||
-- | R.div_ | ||
-- | [ R.button | ||
-- | { onClick: capture_ $ self.setState \s -> s { counter = s.counter + 1 } | ||
-- | , children: [ R.text "Tick!" ] | ||
-- | } | ||
-- | , provider countContext self.state.counter | ||
-- | [ consumer countContext \counter -> | ||
-- | [ R.text $ "Ticks: " <> (show counter) | ||
-- | ] | ||
-- | ] | ||
-- | ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👋 I'm late to the party as this PR has been merged for quite some time, and maybe my following question should have been posted elsewhere. if that's wrong I do apologize 🙇
I've tried using the context API but failed to create a context as it's actually an Effect. This example doesn't cover the creation part. Am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello 👋
You have two options:
- Use
unsafePerformEffect
at the module level to create your context. It bends the rules a tiny bit, but in a safe, predictable way. - Define your context during app initialization. This is a pattern I've been using more often lately. Component creation is actually effectful as well, as noted here and explained more thoroughly here. This is also why the newer hooks api defines component creation as an effect. You can see a more complete example of this pattern used with context here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I missed the notification of your reply. Thank you very much, it confirms what I was suspecting.
I'll go with the first option as I don't have a purescript main entry point in my setup.
The second option is the most appealing obviously. My take on all of this would be that if you have an main entry-point you could totally avoid React context and simply use a MonadReader-like instead (assuming we don't care about interop I guess).
Thank you @spicydonuts 🙇
Add support for https://reactjs.org/docs/context.html
Borrowed ffi definition from purescript-react, and added helper functions.