GeezerVison is showing github.com — Add an example which includes an external component · Issue #2 · purescript-react/purescript-react-basic
Add an example which includes an external component #2DescriptionIt would be good to demonstrate that we can use other components easily. Activitymaddie927 commented on Jan 10, 2018 Would this include to/from functions for purescript-react's ReactComponent type? I'm curious if you already have something in mind for the non-basic cases. I've been thinking about something similar to this but as convenience functions for common patterns in or on top of purescript-react so it's easy to reach for a lifecycle function when you need it. I really like the props setup going on in this library though. maddie927 commented on Jan 10, 2018 Specifically, I was thinking about stealing reason-react's "reducer" component (very similar to elm/pux/redux, but using component state).
Examples:
createStatefulComponent (\props -> initialState) reducer render
createStatefulComponentWithInit InitAction (\props -> initialState) reducer render (componentDidMount)
createFormContainer ??? (don't know how this would work yet but I want it 🙂) paf31 commented on Jan 10, 2018 ContributorAuthor More actions I was thinking more about components from NPM. I haven't really thought too much about adapters, but I think I would prefer for them to be in a separate library. I considered going via purescript-react, but I wanted as few dependencies as possible and the freedom to try different APIs out easily.
This library is pretty much tailor-fit for our use cases right now, but if the need for lifecycle methods comes up, we'll have to find a way to include them, hopefully without complicating the API.
Yes, I expect a Redux/ElmArch layer on top of this would be quite useful. Reacted by maddie, Brady Ouren and Steven MacCoun jgoux commented on Apr 14, 2018 Hello,
were these examples ever added?
I'd be interested in wrapping external components 🌯 paf31 commented on Apr 16, 2018 ContributorAuthor More actions Not yet, although they basically amount to using the FFI to pull in the component class as a value and then using it as normal. maddie927 commented on Apr 16, 2018 Example for (simplified) React Router Route component:
type RouteProps =
{ path :: String
, exact :: Boolean
, render :: MatchedRouteProps -> JSX
}
foreign import route :: ReactComponent RoutePropsReacted by CT Wu and Julien Goux i-am-the-slime commented on May 17, 2019 But what would the js file look like? maddie927 commented on May 17, 2019 Something like this:
"use strict";
var RR = require("react-router");
exports.route = RR.Route;i-am-the-slime commented on May 18, 2019 Thank you very much, for my example (a material UI button) it was this:
foreign import button ::
ReactComponent { onClick :: EventHandler, children :: Array JSX, color :: String, variant :: String }
'use strict'
exports.button = require("@material-ui/core/Button").default;
I'm also curious how I could make all the fields of the props somehow optional. maddie927 commented on May 20, 2019 alextes commented on May 24, 2020 Can this be reopened with the outcome of having an example? Or even multiple examples? There appears to be no information yet on how to deal with external components. Or perhaps as it appears there is no one true way, what I'm looking for is an overview of the options people have thought of. I'll share mine.
The following is all in the context of larger external components as often found in frameworks or libraries.
-
ReactComponent with lots of Data.Nullable. This feels cumbersome to me at around five props up, where three or more props are passed null. It makes the types accurate and helpful, but it makes the JSX communicate a lot of nothing. Additionaly, as you need more props exposed from the external component you have to go back and update all the uses with nulls, or spend time up front to type props you don't yet care about.
-
forall a. ReactComponent (Record a) obviously this is not the PureScript way but nevertheless I notice myself reaching for it as an escape hatch for components with many optional props that are all over the place. For example a button component. Yet, my frustration with the unsafe type brought me here 😄 .
2a. I just thought of this one, I guess you could type the component as if it wants the full record, pass a record that is a subset of it and unsafeCoerce it. At least that way you get to keep the types as information.
type ButtonProps = { onClick :: Effect Unit, disabled :: Boolean }
foreign import button ::
forall props props_. Union props props_ ButtonProps =>
ReactComponent (Record props)
It appears easy to break. I broke it, by moving the union outside the foreign import. Spent time understanding FFI more deeply, fixing it. Similarly, this method appears to break down when some props are sets of props themselves.
- Use
Data.Options. Designed for this scenario. I only tried it superficially myself. Creating the sets of props is a breeze, on the other hand, extra syntax in the middle of JSX, high boilerplate, what about props that are shared between many components? Like children?
jvliwanag commented on May 24, 2020 I need to clean up my lib -- https://github.com/jvliwanag/purescript-oneof . But adding it as an option as well.
It allows for simple record declarations:
type Props =
{ name :: UndefinedOr String
, foo :: UndefinedOr (String |+| Number |+| Boolean)
}
foreign import _myButton :: ReactComponent Props
myButton :: forall r. Coercible r Props => r -> JSX
myButton = element _myButton <<< coerce
sample = myButton { foo: "bar" } -- can omit nameReacted by Alexander Tesfamichael and Adam Barber maddie927 commented on May 26, 2020 I wouldn't mind having an FFI example. You're correct that it's more because there's no one way to do it, and it's not really different from any other PureScript FFI.
- When I'm making a PS component which wraps a JS one and that JS component is otherwise hidden from the outside world, I reduce the Nullable noise by not defining props I won't use and making props I always use non-nullable, even if they're technically optional in the JS component. For example, if I'm wrapping a button component I will probably define
onClick :: EventHandler and just always provide it, even if there are cases where it's a noop.
- btw, you can define a "defaults" props record alongside your component, allowing you to call it like
Button.button Button.defaults { onClick = do something } -- this allows you to add new props to the component without breaking existing usage, and this isn't specific to FFI components
-
Yeah, once in a while I do this to hack something quickly, but options 1 or 3 are almost always better.
-
This is great for simple components with lots of props, like the DOM components. It's useful when the FFI component is extremely flexible and you need to expose that in PS without lots of boilerplate. Like you said, though, it can have issues if any props have complicated types, like nested records. I would generally recommend the Data.Options approach.
-
Yep, this is a good option
-
One other option which is sometimes appropriate -- split the definition into two or more components. Sometimes certain props are required in combination. Defining the component multiple times with different props can simplify basic use cases while also making more complicated ones safer.
alextes commented on May 27, 2020 Lots of good options, some new to me. Thanks!
MetadataMetadataDevelopmentNo branches or pull requestsIssue actions
|