Performance and potential changes to allow typeclasses on props
Closed this issue · 0 comments
As our applications grow, the disconnect between PureScript's tendency toward constantly creating functions (currying, lots of callback props) and objects (data constructors) and React's reliance on reference equality for optimization is becoming apparent. There are a few cases where we'd like to use Eq or a manual equality implementation rather than React's shallow reference equality checks, but this isn't possible with the current API.
Additionally, the new context API is a lot more type-friendly so this might be a good time to experiment with that a little.
After exploring reason-react's approach a bit, I think both typeclasses and context may be possible by splitting the "createClass" and "implement render and lifecycles" bits into separate pieces:
-- | technically this isn't pure, but that's already the
-- | case for react-basic 2's `component` function
componentClass :: forall props. React.Class props
componentClass = component "Component"
-- | currently `Component` is synonymous with JS React
-- | classes, but it might make sense to change that and
-- | add a `toReactClass` utility instead (you'd need to resolve
-- | any typeclass constraints when calling `toReactClass`)
component :: forall props. Eq props => React.Component props
component = ...combine render and lifecycles with `componentClass` (reason-react uses object spread, maybe a helper function would be necessary)
where
render props = ...Having componentClass extracted from the main component definition keeps it from being recreated on every render (this currently prevents typeclass use). It also opens the api up a bit for distinguishing "configuration" from "props" (or maybe "static props" from "dynamic props"). The former would be arguments which don't change as your application runs, while the latter would be passed as normal React props. This means api implementations and callbacks can be passed without tricking React into always rerendering:
x config = stateless { render }
where
render props =
element someComponent { getData, onClick } { id }This means less work for React itself, but it also allows this optimization:
x config = stateless { render }
where
render props =
someComponentPreapplied { id }
someComponentPreapplied = element someComponent { getData, onClick }