Skip to content

cuzfrog/simple-sri

Repository files navigation

Simple Scalajs-React-Interface

Build Status Scala.js Maven Central

Lightweight scalajs react solution.

Ported react version: 16

Features

  • Simple and straightforward style to build react component.
  • Use diode instead of redux to manage state.
  • Write your DOM tests side by side with scala-jest.

Setup

Dependencies:

val sriVersion = "0.3.0"
libraryDependencies ++= Seq(
    "com.github.cuzfrog" %%% "simple-sri" % sriVersion,
    "com.github.cuzfrog" %%% "simple-sri-diode" % sriVersion, //Diode connector
    "com.github.cuzfrog" %%% "simple-sri-test-utils" % sriVersion % Test
)

Example

Define React component:

import sri.react._
import sri.web.vdom.tagsPrefix_<^._

class BasicInput extends Component[BasicInput.Props, BasicInput.State] {
  override def getInitialState = BasicInput.State("")

  override def render(): ReactRenders = {
    <.input(
      ^.value := state.value,
      ^.onChange := callback
    )
  }

  private val callback = (event: ReactEventI) => {
    val value = event.target.value
    setState(s => s.copy(value = value))
    println(value)
  }
}

object BasicInput {
  def apply(props: Props = Props()): ReactElement = CreateElement[BasicInput](props)

  case class State(value: String)
  case class Props()
}

You could use ComponentP, ComponentS to build component that only has Props or State.

Connect with diode circuit:

Define actions and models:

import diode.Action
case class FilterChange(v: String) extends Action
case class RootModel(filterModel: FilterModel)
case class FilterModel(filterValue: String, filteredElements: Seq[String])

Define diode circuit:

object AppCircuit extends Circuit[RootModel] with ReactConnector[RootModel] {...}

Connect to component:

class FilterInput extends ComponentP[FilterInput.Props] {...}

object FilterInput {
  case class Props(value: String, onChange: ReactEventI => Unit)

  def apply(): ReactElement = {
    AppCircuit.connect(_.filterModel) { proxy =>
      def value: String = proxy().filterValue
      val onChange: ReactEventI => Unit = (event: ReactEventI) => {
        val v = event.target.value
        println(s"filter input event! $v | $value")
        event.defaultPrevented
        proxy.dispatch(FilterChange(v))
      }
      CreateElement[FilterInput](Props(value, onChange))
    }
  }
}

You can find examples in tests sub-project.

Document

Component

A scala class wrapped in a PrototypeComponent, delegating functionalities to each other. Thus js native methods have been isolated from the client.

Component can be abstract and have parameters, cause they are common classes:

abstract class AbstractComponent[P,A](args:A) extends ComponentP[P]{...}

But concrete component that is to be instantiated to react element cannot have arguments.

Factory CreateElement provides ways to create react element. Clients do not need to manage instances.

Test

See examples in project tests.

Live example: run sbt tests/fastOptJS, then npm start, a FilterList could be accessed on localhost:8080

About

This project derives from scalajs-react-interface by @chandu0101.

Author: Cause Chung (cuzfrog@139.com)

License: Apache License Version 2.0