based on code generated by react-native init
by Christopher J. Brody aka @brodybits (Chris Brody)
LICENSE: ISC OR MIT
Simple counter app demo with state/action management system based on Hyperapp API, using elements supported by react-primitives
, working on React Native and react-native-web
. Inspired by Hyperapp demo in https://github.com/hyperapp/hyperapp#getting-started.
MOTIVATION:
- jorgebucaran/hyperapp#168 - desire to use Hyperapp API on React Native
- https://medium.com/hyperapp/hyperapp-for-redux-refugees-2507c9dd1ddc
- jorgebucaran/hyperapp#641 (desire to use Superfine as a dependency), especially rejected idea in jorgebucaran/hyperapp#641 (comment) (remove VDOM from Hyperapp)
- jorgebucaran/hyperapp#672 (desire to experiment with Hyperapp 2.0 API on React Native as well)
See also: https://github.com/brodybits/hyperapp-rewrite-demo-on-inferno-and-superfine - demo rewrite of Hyperapp state/action management working with functional (stateless) components on multiple VDOM APIs: Inferno (React API) and Superfine
NOTE: This project no longer conforms to the Hyperapp API for specifying actions and views. Version with partial conformance to Hyperapp 1.x API is available in the strict-api-1
branch.
First step: npm install
Android: react-native run-android
iOS: react-native run-ios
or open ios/HyperappLikeNativeViewDemo.xcodeproj
and run from Xcode
(using react-native-web
)
Paste the contents of App.js
into App.js
in https://codesandbox.io/s/q4qymyp2l6
(see react-native-web#quick-start
)
see below
Top-level app functions with initial state, actions, effects (side effects such as I/O, timers, I/O, other asynchronous operations, and other non-pure functions), and view in JSX (partially inspired by Hyperapp demo app in https://github.com/hyperapp/hyperapp#getting-started):
const App = () => (
<ManagedAppView
state={{ count: 0 }}
actions={{
up: (state) => ({ count: state.count + 1 }),
dn: (state) => ({ count: state.count - 1 }),
}}
effects={{
up3: (actions, effects) => {
actions.up()
setTimeout(effects.up2, 400)
},
up2: (actions, effects) => {
actions.up()
setTimeout(actions.up, 400)
},
dn3: (actions, effects) => {
actions.dn()
setTimeout(effects.dn2, 400)
},
dn2: (actions, effects) => {
actions.dn()
setTimeout(actions.dn, 400)
},
}}>
<MyAppView />
</ManagedAppView>
)
const MyAppView = ({ state, actions, effects }) => (
<View style={styles.container}>
<Text style={styles.welcome}>
Hyperapp micro rewrite demo on React Native
</Text>
<Text>···</Text>
<MyTouchButton
style={styles.mybutton}
onPress={effects.up3}
title="Up 3"
/>
<Text>···</Text>
<MyTouchButton
style={styles.mybutton}
onPress={actions.up}
title="Up (+1)"
/>
<Text style={styles.welcome}>
{state.count}
</Text>
<MyTouchButton
style={styles.mybutton}
onPress={actions.dn}
title="Down (-1)"
/>
<Text>···</Text>
<MyTouchButton
style={styles.mybutton}
onPress={effects.dn3}
title="Down 3"
/>
</View>
)
export default App
Generic ManagedAppView
component that supports the Hyperapp action/state/view API:
const ManagedAppView = createReactClass({
getInitialState () {
const ac = {}
const ef = {}
const self = this
for (let a in this.props.actions) {
ac[a] = () => {
self.setState(prev => ({ ac: ac, st: (this.props.actions[a](prev.st)) }))
}
}
for (let e in this.props.effects) {
ef[e] = () => {
this.props.effects[e](ac, ef)
}
}
return { ac: ac, st: this.props.state, ef: ef }
},
render () {
return React.Children.map(this.props.children, ch => (
React.cloneElement(ch, { state: this.state.st, actions: this.state.ac, effects: this.state.ef })
))
}
})
Functional MyTouchButton
component using TouchableWithoutFeedback
imported as Touchable for portability to react-primitives
:
const MyTouchButton = (props) => {
const { onPress, title, ...other } = props
return (
<View {...other}>
<Touchable onPress={onPress}>
<Text>{title}</Text>
</Touchable>
</View>
)
}
Demo styles with help from react-native init
and guidance in https://facebook.github.io/react-native/docs/touchablehighlight:
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
mybutton: {
alignItems: 'center',
backgroundColor: '#DDDDDD',
padding: 10
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
})
--- a/App.js
+++ b/App.js
@@ -17,9 +17,9 @@ import createReactClass from 'create-react-class'
import {
StyleSheet,
Text,
- TouchableWithoutFeedback as Touchable,
+ Touchable,
View
-} from 'react-native'
+} from 'react-primitives'
const App = () => (
<ManagedAppView
- Add
react-primitives
on codesandbox.io or use a fork such as https://codesandbox.io/s/xvzmvylo8o - Apply the changes above to App.js before pasting into codesandbox.io
npm install react-primitives
- Apply the changes above to App.js
TBD
- Integrate build and run on browser using
react-native-web
(#1) - Nice touch button onPress animation
- (BREAKING) View API changes from "Hyperapp 2.0", hopefully closer to standard functional component API (brodybits/hyperapp-rewrite-demo-on-inferno-and-superfine#5)
- Pass event data to action and effect functions
- Make this even more functional (#7) ref: https://www.bignerdranch.com/blog/destroy-all-classes-turn-react-components-inside-out-with-functional-programming/
- Publish generic (common) functionality in one or more npm packages
- improve styling
- CC0 (public domain) API specification (brodybits/hyperapp-rewrite-demo-on-inferno-and-superfine#1)
- demo on https://github.com/dabbott/react-native-web-player
- TodoMVC app, likely based on https://github.com/dangvanthanh/hyperapp-todomvc
- other open issues