• Stars
    star
    132
  • Rank 274,205 (Top 6 %)
  • Language
    Scala
  • License
    Apache License 2.0
  • Created over 10 years ago
  • Updated almost 10 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

ScalaJS interface for Facebook React

scala-js-react

Build Status Gitter

Scala-js-react provides nice statically typed interface to Facebook's React.

Quickstart

For detailed sbt configuration please refer to scala.js documentation.

build.sbt

enablePlugins(ScalaJSPlugin)

scalaVersion := "2.11.5"

libraryDependencies ++= Seq(
  "com.xored.scalajs" %%% "scalajs-react" % "0.3.3",
  compilerPlugin("org.scalamacros" % "paradise" % "2.0.1" cross CrossVersion.full)
)

project/plugins.sbt

addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.0")

project/build.properties

sbt.version=0.13.7

Features

scala-js-react aims to support all Facebook React features.

scalax annotation

While Facebook React uses JSX, scala-js-react offers scalax support. Basically scalax allows to use Scala XML literals to build React DOM.

React DOM allows to put objects into attribute values, while scala.xml.UnprefixedAttribute constructor takes Seq[Node] or String. So we have to transform methods before it typechecks. That is why scalax scalax uses macro annotations and requires macro paradise compiler plugin.

object HelloMessage extends TypedReactSpec {

  case class State()
  case class Props(name: String)

  def getInitialState(self: This) = State()

  @scalax
  def render(self: This) = {
    <div>Hello {self.props.name}</div>
  }
}

React.renderComponent(
  HelloMessage(HelloMessage.Props(name = "John")),
  mountNode
)

Internal State

A component can maintain internal state.

object Timer extends TypedReactSpec with TypedEventListeners {

  case class Props()
  case class State(secondsElapsed: Int, interval: Option[Int])

  def getInitialState(self: This) = State(secondsElapsed = 0, interval = None)

  implicit class Closure(self: This) {
    import self._

    val tick = () => {
      setState(state.copy(secondsElapsed = state.secondsElapsed + 1))
    }
  }

  override def componentDidMount(self: This) = {
    val interval = window.setInterval(self.tick, 1000)

    self.setState(self.state.copy(interval = Some(interval)))
  }

  override def componentWillUnmount(self: This) = {
    self.state.interval.foreach(window.clearInterval)
  }

  @scalax
  def render(self: This) = {
    <div>Seconds Elapsed: {self.state.secondsElapsed}</div>
  }
}

Typed listeners and closures

object Say extends TypedReactSpec with TypedEventListeners {

  case class Props()
  case class State(text: String)

  implicit class Closure(self: This) {
    import self._

    val onChange = input.onChange(e => {
      setState(state.copy(text = e.target.value))
    })

    val onClick = button.onClick(e => {
      alert(state.text)
    })
  }

  def getInitialState(self: This) = State(text = "")

  @scalax
  def render(self: This) = {
    <div>
      <input type="text" value={self.state.text} onChange={self.onChange}></input>
      <button type="text" onClick={self.onClick}>Say</button>
    </div>
  }
}

How to run examples

$ sbt "project scalajs-react-examples" fastOptJS
$ open scalajs-react-examples/index.html

Copyright

Copyright Β© 2014 Xored Software, Inc.

Licensed under the Apache License, Version 2.0.