joelburget / react-haskell

React bindings for Haskell
MIT License
351 stars 26 forks source link

native class interop #9

Open joelburget opened 9 years ago

joelburget commented 9 years ago

I want to use JS-defined react classes. Once imported they should behave exactly the same as react-haskell classes.

Also see issue #8 for more on classes.

johncant commented 9 years ago

For interop we need to be able to pass "props" when we render a class. Are you interested in using Haskell-defined react classes from JS? It looks like React has support for its own dynamic type checking http://facebook.github.io/react/docs/reusable-components.html which we could utilize! Unfortunately I feel as though we'll need yet another type variable props for each class.

joelburget commented 9 years ago

Hey John, can you elaborate on what you're thinking with some examples? I understand what you're getting at, but would like a concrete example so we can hash out the details.

johncant commented 9 years ago

Hi Joel, was going to contribute more to this repo this week, but unfortunately the rest of my life got slightly in the way. I think I am close to getting composable classes (React 12.2), but it will certainly break animations, which I would need to fix before I could expect you to accept a PR. I also need to read up on the React 13.0b chances and flux, so I can think more about #8 .

So, when you instantiate a react JS class using createElement, you pass it a props hash. In react HS, we had better be able to

Maybe that's for another issue on here, but for basic interop, how about something like:

importing someone's javascript class:

import Haste.Foreign
import React.Foreign -- TODO

-- import the class
data LaunchControlProps = LaunchControlProps { countDown :: Int, capsule :: String }

instance ToProps LaunchControlProps where
  toProps = ffi "function(cd,c){return {countDown: cd, capsule: c}}" -- Still unsure how to make a JS hash without using the ffi or JSON. I must look really stupid.

launchControl :: ReactClass () () () LaunchControlProps
launchControl = importClass "launchControlReactClassImplementedInJavaScript"

-- markup
reactClass_ launchControl $ LaunchControlProps 10 "Soyuz"

exporting a Haskell React class

import Haste.Foreign
import React.Foreign

-- Create a class using Haskell

data RocketProps = RocketProps { throttle :: Double, thrust :: Double }

--   this could rather cunningly define propTypes
instance FromProps RocketProps where
  fromProps props = RocketProps t f
  where (t,f) = ffi "function(props) {return [props.throttle, props.thrust]}"

rocketPanel :: ReactClass Foo Bar Quux RocketProps
rocketPanel = ...

-- export the class

main :: IO ()
  exportClass "RocketPanel" rocketPanel

What do you reckon?