Created
March 3, 2016 22:18
-
-
Save tel/84b73b80e3120747b39c to your computer and use it in GitHub Desktop.
Scala.js Elm-alike
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package tutorial.webapp | |
import japgolly.scalajs.react._ | |
import japgolly.scalajs.react.vdom.prefix_<^._ | |
import org.scalajs.dom | |
import scala.scalajs.js.JSApp | |
trait Component { | |
type Params | |
type State | |
type Action | |
def init(p: Params): State | |
def control(a: Action)(s: State): State | |
def view(s: State, submit: Action => Unit): ReactElement | |
} | |
object Counter extends Component { | |
type State = Int | |
type Params = State | |
abstract class Action | |
case class Increment() extends Action | |
case class Decrement() extends Action | |
def init(p: Params): State = p | |
def view(s: State, submit: Action => Unit): ReactElement = { | |
<.div( | |
<.span( | |
^.classID := "lalala", | |
s | |
), | |
<.button("+", ^.onClick --> Callback{submit(Increment())}), | |
<.button("-", ^.onClick --> Callback{submit(Decrement())}) | |
) | |
} | |
def control(a: Action)(s: State): State = a match { | |
case Increment() => s + 1 | |
case Decrement() => s - 1 | |
} | |
} | |
object CounterSet extends Component { | |
type Params = Unit | |
type State = List[Counter.State] | |
abstract class Action | |
case class PushCounter(p: Int) extends Action | |
case class PopCounter() extends Action | |
case class ActCounter(index: Int, act: Counter.Action) extends Action | |
def actCounter(index: Int)(act: Counter.Action): Action = | |
ActCounter(index, act) | |
def init(p: Params): State = List() | |
def view(s: State, submit: Action => Unit): ReactElement = { | |
val counters = s.zipWithIndex.map { | |
case (state, index) => | |
val localSubmit = submit compose actCounter(index) | |
Counter.view(state, localSubmit) | |
} | |
<.div( | |
<.div(^.id := "counters", counters), | |
<.button("Add Counter", ^.onClick --> Callback{submit(PushCounter(0))}), | |
<.button("Remove Counter", ^.onClick --> Callback{submit(PopCounter())}) | |
) | |
} | |
def control(a: Action)(s: State): State = a match { | |
case PushCounter(p) => Counter.init(p) +: s | |
case PopCounter() => s.drop(1) | |
case ActCounter(index, act) => s splitAt index match { | |
case (fore, Nil) => fore | |
case (fore, counter :: hind) => | |
val newHind = Counter.control(act)(counter) :: hind | |
fore ++ newHind | |
} | |
} | |
} | |
object TutorialApp extends JSApp { | |
type State = CounterSet.State | |
type Action = CounterSet.Action | |
var root: State = CounterSet.init() | |
// Update the app state | |
def submit(a: Action): Unit = { | |
root = CounterSet.control(a)(root) | |
render() | |
} | |
def render(): Unit = { | |
ReactDOM.render(CounterSet.view(root, submit), dom.document.body) | |
} | |
def main(): Unit = { | |
render() | |
} | |
} |
And I really want something more lens like here.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Not sure how to remove duplication occurring on L85. Feels like I ought to be able to extend an object or something.