purescript-contrib/purescript-react

Functional Components

i-am-tom opened this issue · 2 comments

In React, there is a notion of "functional components" (which is to say, components defined as a single function). In essence, this is just the render function, with props as the argument:

var MyElement = ({ x, y, z }) =>
  <div id={x}>
    <a href={y}>{z}</a>
  </div>

These are both easier to read and promise future optimisations, so it would be good to get them involved. As I see it, there are two main cases where one can't use these:

  • Anything involving component lifecycle (shouldComponentUpdate, componentDidMount)
  • Anything involving state (getInitialState, setState, etc)

In these cases, we would need to fall back to class-declared components. There's a pretty trivial way to "lift" a stateless component into a class, should that need arise, which is why I'm here.

Could this library benefit from favouring the "functional" presentation of components where possible? My initial-thoughts-over-lunch involved a typeclass-based approach:

class WithState a b | a -> b
instance classWithState :: WithState ClassBased ClassBased
instance functionalWithState :: WithState FunctionalBased ClassBased

We can use functional dependencies to express how modifications will affect the given inputs. It could also be approached similarly to lens composition: certain operations "weaken" a FunctionalElement to a ClassDeclaration, for example.

I must admit that I haven't thought about this to a level that I'm satisfied with yet, but Phil suggested posting an issue so we could talk about it. What do people think?

coot commented

You only have to be careful to resolve type classes before using a component. Check #105. But in this case it should be fine.

ethul commented

I like this idea. Actually, I have a somewhat related comment in #109 (comment). Do you happen to have an example along the lines of what you are proposing? I think going class-based would be a nice approach to functional components, over the current approach:

-- | Create a stateless React class.
createClassStateless :: forall props.
(props -> ReactElement) -> ReactClass props
createClassStateless = unsafeCoerce