Skip to content

Instantly share code, notes, and snippets.

@bodhi
Last active February 12, 2017 11:21
Show Gist options
  • Save bodhi/a1327cda84cec1ac37978b5189b22f48 to your computer and use it in GitHub Desktop.
Save bodhi/a1327cda84cec1ac37978b5189b22f48 to your computer and use it in GitHub Desktop.
React Native backend for Pux
"use strict";
var React = require("react");
var ReactNative = require("react-native")
var AppRegistry = ReactNative.AppRegistry;
function reactClass(htmlSignal) {
return React.createClass({
componentWillMount: function () {
var ctx = this;
htmlSignal.subscribe(function () {
ctx.forceUpdate();
});
},
render: function () {
return htmlSignal.get()
}
});
}
exports.registerComponent = function (name) {
return function registerComponent(signal) {
var elem = reactClass(signal);
AppRegistry.registerComponent(name, function() { return elem });
return function () {};
}
}
var fromReact = function (comp) {
return function (attrs) {
return function (children) {
if (Array.isArray(children[0])) children = children[0];
var props = attrs.reduce(function (obj, attr) {
var key = attr[0];
var val = attr[1];
obj[key] = val;
return obj;
}, {});
return React.createElement.apply(null, [comp, props].concat(children))
};
};
};
exports.view = fromReact(ReactNative.View);
exports.text = fromReact(ReactNative.Text);
exports.raw = function (text) {
return text;
};
exports.attr = function (key) {
return function (val) {
return [key, val];
};
};
exports.listView = function(render) {
return function(list) {
var ds = new ReactNative.ListView.DataSource({ rowHasChanged: function(a, b) { return a != b }});
var l = ds.cloneWithRows(list);
return fromReact(
function(props) {
return React.createElement(ReactNative.ListView, Object.assign({}, { renderRow: render, dataSource: l }, props));
}
)
}
}
var test = require("../../temp").default
exports.test = fromReact(test);
module Native (app) where
import Prelude (Unit, bind, ($), (+), (-), show, (<>), (<<<), pure, map)
import Control.Monad.Eff (Eff)
import Pux.Base (start, Update, element, noEffects, EffModel)
import Pux.Html.Elements (Attribute)
import Data.Function.Uncurried (runFn3)
import Control.Monad.Eff.Exception (EXCEPTION)
import Signal (Signal, (~>))
import Signal.Channel (CHANNEL)
import Signal.Time (every)
import Data.List
import Control.Monad.Aff (attempt)
import Network.HTTP.Affjax (AJAX, get)
import Data.Either
import Data.Argonaut.Decode (class DecodeJson, decodeJson, (.?))
import Data.Foldable (foldl)
foreign import data Native :: * -> *
foreign import registerComponent :: forall a eff. String -> Signal (Native a) -> Eff eff Unit
foreign import data Text :: * -> *
data NativeText a = N (Native a) | Text String
type Element a = Array (Attribute a) -> Array (Native a) -> Native a
foreign import view :: forall a. Element a
foreign import test :: forall a. Element a
text :: forall a. Array (Attribute a) -> Array (NativeText a) -> Native a
text a c = _text a $ map toNative c
where toNative :: NativeText a -> Native a
toNative (N a) = a
toNative (Text s) = raw s
foreign import _text :: forall a. Array (Attribute a) -> Array (Native a) -> Native a
foreign import listView :: forall item a. (item -> Native a) -> Array item -> Element a
-- Bad type, it needs to be embedded inside <Text>
foreign import raw :: forall a. String -> Native a
foreign import attr :: forall a v. String -> v -> Attribute a
--------------------------------------------------
data Action = RequestTodos | ReceiveTodos (Either String Todos)
type State =
{ todos :: Todos
, status :: String }
type Todos = Array Todo
newtype Todo = Todo
{ id :: Int
, title :: String }
instance decodeJsonTodo :: DecodeJson Todo where
decodeJson json = do
obj <- decodeJson json
id <- obj .? "id"
title <- obj .? "title"
pure $ Todo { id: id, title: title }
fetchTodos = do
res <- attempt $ get "https://jsonplaceholder.typicode.com/users/1/todos"
let decode res = decodeJson res.response :: Either String Todos
let todos = either (Left <<< show) decode res
pure $ ReceiveTodos todos
update :: Action -> State -> EffModel State Action (ajax :: AJAX)
update (ReceiveTodos (Left err)) state =
noEffects $ state { status = "Error fetching todos: " <> show err }
update (ReceiveTodos (Right todos)) state =
noEffects $ state { todos = todos, status = "Todos" }
update (RequestTodos) state =
{ state: state { status = "Fetching todos..." }
, effects: [ fetchTodos ]
}
wrapper = view [ attr "style" { flex: 1, alignItems: "stretch", backgroundColor: "red", paddingTop: 60 } ]
todoView :: Todo -> Native Action
todoView (Todo { id, title }) = text [] [ Text (show id <> ": " <> title) ]
v :: State -> Native Action
v { todos, status } = wrapper [ listView todoView todos [] []
, text [] [ Text status ]
, test [] []
]
--u :: String -> Native Action
--u s = text [] [ s ]
app :: Eff (err :: EXCEPTION, channel :: CHANNEL, ajax :: AJAX) Unit
app = do
a <- start
{ initialState: { todos: [Todo { title: "initial", id: 0 }]
, status: ""
}
, update
, view: v
, inputs: [
-- every 5000.0 ~> \_ -> RequestTodos
]
}
registerComponent "mobile" a.html
@bodhi
Copy link
Author

bodhi commented Feb 12, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment