object Main extends js.JSApp {
def main(): Unit = {
val rootNode = dom.document.getElementById("playground")
ReactDOM.render(EditableSortableListDemo.c(), rootNode)
frp()
}
def frp()(implicit ctx: Ctx.Owner)={
import rx._
val a = Var(1); val b = Var(2)
val c = Rx{ a() + b() }
println(c.now) // 3
a() = 4
println(c.now) // 6
}
}
> fastOptJS
[info] Compiling 1 Scala source to /Users/joco/dev/scala.js/react/sjs-playaround/stable/target/scala-2.11/classes...
[error] /Users/joco/dev/scala.js/react/sjs-playaround/stable/src/main/scala/Demo/Main.scala:16: No implicit Ctx.Owner is available here!
[error] frp()
[error] ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 1 s, completed Dec 8, 2016 7:11:06 AM
>
a.update
before. The difference between using a.now
and a()
on the right hand side is that a()
can be used only inside reactive context. a.now
can be used outside reactive context in which it gives the current value of a
and inside reactive context in which it doesn't add a dependency to a
from the reactive variable that the context is computing. Contrast this with using a()
inside the context which adds a dependency
a() = 5
is exactly the same as a.update(5)
I don’t think this has anything to do with map
or functor laws, as replacing map
with the corresponding Rx
construct leads to the same problem:
import $ivy.`com.lihaoyi::scalarx:0.3.2`, rx._
object Example {
val v1 = Var(0)
val v2 = Rx { v1() }
val v22 = Rx { v1() }
val v23 = Rx { v22() }
val v3 = Rx { v23() }
def q(implicit trackDependency: Ctx.Data) = {
if (v1() == 0) v2()
else {
val b = v3() != v2()
if (b)
103
else
17
}
}
val v = Rx { q }
val list = {
var result = List.empty[Int]
val obs = v.trigger { result = result :+ v.now }
v1() = 1
v1() = 2
result
}
}
println(Example.list)
This prints List(0, 103, 17)
instead of List(0, 17)
, too.
Hi,
I've got a problem with calling Futures out of Rx.
Just copy and paste the following code into ScalaFiddle:
import rx._
import rx.async._
import scala.concurrent.Future
import scala.concurrent.Promise
import scala.concurrent.ExecutionContext.Implicits.global
def request(id: Int): Future[String] = {
val p = Promise[String]()
js.timers.setTimeout(500) {
println(s"Request: $id")
p.success(id.toString)
}
p.future
}
val id = Var[Int](0)
val idString = id.flatMap(i => request(i).toRx("..."))
id() = 10
println("End...")
And you fall into a loop, with the following output:
End...
Request: 0
Request: 10
Request: 10
Request: 10
Request: 10
Request: 10
Request: 10
Request: 10
etc....
Is this a known behaviour? or is this a bug?
Is there a workaround for this kind of pattern?
Thanks for your help.
Roll
@rreckel Yea, currently the way flatMap works, it recreates the inner rx whenever the inner rx changes - this interacts poorly with toRx because, as you see in your test, it throws it in an infinite loop.
Im having a hard time coming up with an alternate definition of toRx that actually works within flatmap and am considering just removing it all together.
So ive been playing around with alternatives, and this seems to work:
implicit class FutureCombinators[T](val v: rx.Rx[Future[T]]) extends AnyVal {
def flatten(initial: T)(implicit ec: ExecutionContext, ctx: Ctx.Owner): Rx[T] = {
var result = Var(initial)
v.foreach { x => x.foreach(result.update) }
result
}
}
And its used this way:id.map { x => request(x) }.flatten("...")
I tried your flatten function:
import rx._
import rx.async._
import scala.concurrent.Future
import scala.concurrent.Promise
import scala.concurrent.ExecutionContext
implicit class FutureCombinators[T](val v: rx.Rx[Future[T]]) extends AnyVal {
def flatten(initial: T)(implicit ec: ExecutionContext, ctx: Ctx.Owner): Rx[T] = {
val result = Var(initial)
v.foreach { x => x.foreach(result.update) }
result
}
}
def request(id: Int): Future[String] = {
val p = Promise[String]()
js.timers.setTimeout(500) {
println(s"Request: $id")
p.success(id.toString)
}
p.future
}
import scala.concurrent.ExecutionContext.Implicits.global
val id = Var[Int](0)
val idString = id.map(i => request(i)) .flatten("...")
val result = for {
i <- id
is <- idString
} yield s"$i -> $is"
result.foreach(println(_))
id() = 10
id() = 20
println("End...")
This code generates the following result in ScalaFiddle:
0 -> ...
10 -> ...
20 -> ...
End...
Request: 0
20 -> 0
Request: 10
20 -> 10
Request: 20
20 -> 20
This is not exactly what I expected..... but still better than an infinite loop ;-)
What do you think?